如果我想使用预处理器
我正在设计自己的
如果我使用
或者它是否每次都会扩展到以下内容:
#define
语句来方便定义和计算常量和常用函数并利用较少的RAM开销(与使用const
值相比),但是如果多个宏一起使用,我不确定它们如何解析。我正在设计自己的
DateTime
代码处理,类似于Linux时间戳,但适用于每秒更新60次的游戏。我更喜欢声明链接值,但不确定硬编码的值是否会更快。#include <stdint.h>
// my time type, measured in 1/60 of a second.
typedef int64_t DateTime;
// radix for pulling out display values
#define TICKS_PER_SEC 60L
#define SEC_PER_MIN 60L
#define MIN_PER_HR 60L
#define HRS_PER_DAY 24L
#define DAYS_PER_WEEK 7L
#define WEEKS_PER_YEAR 52L
// defined using previous definitions (I like his style, write once!)
#define TICKS_PER_MIN TICKS_PER_SEC * SEC_PER_MIN
#define TICKS_PER_HR TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR
#define TICKS_PER_DAY TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR * HRS_PER_DAY
// ... so on, up to years
//hard coded conversion factors.
#define TICKS_PER_MIN_H 3600L // 60 seconds = 60^2 ticks
#define TICKS_PER_HR_H 216000L // 60 minutes = 60^3 ticks
#define TICKS_PER_DAY_H 5184000L // 24 hours = 60^3 * 24 ticks
// an example macro to get the number of the day of the week
#define sec(t)((t / TICKS_PER_DAY) % DAYS_PER_WEEK)
如果我使用
sec(t)
宏,它使用TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR * HRS_PER_DAY
定义的TICKS_PER_DAY
,那么是否要在调用sec(t)
的代码中处处都进行修改?(t / 5184000L) % 7L)
或者它是否每次都会扩展到以下内容:
(t / (60L * 60L * 60L * 24L)) % 7L)
为什么需要在每个步骤执行额外的乘法指令?这是宏和常量变量之间的平衡取舍,还是我对预处理器的工作原理有误解?
更新:
根据许多有用的答案,将宏链接成常量表达式的最佳设计是用括号包装定义。
1. 正确的操作顺序:
(t / 60 * 60 * 60 * 24) != (t / (60 * 60 * 60 * 24))
2. 通过将常量值分组,鼓励编译器进行常量折叠:
// note parentheses to prevent out-of-order operations
#define TICKS_PER_MIN (TICKS_PER_SEC * SEC_PER_MIN)
#define TICKS_PER_HR (TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR)
#define TICKS_PER_DAY (TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR * HRS_PER_DAY)
sec
的定义中去除分号,这样它就能够扩展成一个表达式。否则类似于sec(x) + 10
的东西是不会工作的。 - Tom Karzes