如何在C中解析链接的宏? [英] How are chained macros resolved in C?

查看:91
本文介绍了如何在C中解析链接的宏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我想使用预处理器#define语句来轻松定义和计算常量及通用函数,并利用较少的RAM开销(与使用const值相反).但是,如果将多个宏一起使用,我不确定如何解决它们.

If I want to use preprocessor #define statements for easy definition and calculation of constants and common functions and take advantage of less RAM overhead (as opposed to using const values). However, I am unsure as to how they are resolved if many macros are used together.

我正在设计自己的DateTime代码处理程序,类似于linux时间戳,但是对于带有滴答更新的游戏来说,该更新代表了1/60秒.我宁愿声明链接的值,但想知道硬编码的值是否会执行得更快.

I'm designing my own DateTime code handling, similar to linux timestamps but for a game with tick updates that represent 1/60th of a second. I would prefer to declare values chained, but wonder if hard coded valued would perform faster.

#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)宏(该宏使用由3个先前的宏TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR * HRS_PER_DAY定义的TICKS_PER_DAY),则会在调用sec(t)的代码中放置所有位置:

If I use the sec(t) macro, which uses TICKS_PER_DAY which is defined by 3 previous macros TICKS_PER_SEC * SEC_PER_MIN * MIN_PER_HR * HRS_PER_DAY, does that place everywhere in my code that calls sec(t):

(t / 5184000L) % 7L)

还是每次都会扩展到:

(t / (60L * 60L * 60L * 24L)) % 7L)

以便在每个步骤执行额外的乘法指令?这是宏和const变量之间的折衷,还是我误解了预处理器的工作原理?

so that extra multiplication instructions are executed at each step? Is this a tradeoff between macros and const variables, or do I misunderstand how the preprocessor works?

更新:

对于每个有用的答案,将宏扩展为常量表达式的最佳链接设计是将定义包装在括号中,用于

Per many helpful answers, the best design for chaining macros which expand into constant expressions is to wrap the definition in parentheses for

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)

推荐答案

请参见 gcc预处理程序宏文档,尤其是类对象宏.

我认为编译器也在这里起作用.例如,如果我们仅考虑预处理器,则应将其扩展为

I think the compiler also comes into play here. For example, if we are only considering the preprocessor, then it should expand to

(t / (60L * 60L * 60L * 24L)) % 7L)

但是,可能是编译器(不管优化如何?)将解决此问题

However, it may be that the compiler (regardless of optimization?) will resolve this to

(t / 5184000L) % 7L)

由于它们是独立的常量,因此可以更快/更简单地执行代码.

since these are independent constants and therefore would be faster/simpler code execution.

注意1:您应该在定义中使用(t)",以防止意外的扩展/解释. 注意2:另一个最佳实践是避免使用undef,因为这会使代码的可读性降低.请参阅有关此操作如何影响宏扩展的说明(类对象宏部分).

Note1: you should use "(t)" in your definition to protect against unintended expansions/interpretations. Note2: another best practice is to avoid using undef, because this makes the code less readable. See the notes about how the macro expansion is affected by this (section Object-like Macros).

更新:来自类似对象的宏:

当预处理器扩展宏名称时,宏的扩展替换宏调用,然后检查扩展是否有更多宏要扩展.例如,

When the preprocessor expands a macro name, the macro's expansion replaces the macro invocation, then the expansion is examined for more macros to expand. For example,

#define TABLESIZE BUFSIZE #define BUFSIZE 1024 TABLESIZE ==> BUFSIZE ==> 1024 首先扩展TABLESIZE以产生BUFSIZE,然后扩展该宏以产生最终结果1024.

#define TABLESIZE BUFSIZE #define BUFSIZE 1024 TABLESIZE ==> BUFSIZE ==> 1024 TABLESIZE is expanded first to produce BUFSIZE, then that macro is expanded to produce the final result, 1024.

请注意,在定义TABLESIZE时未定义BUFSIZE. TABLESIZE的"#define"将完全使用您指定的扩展名(在本例中为BUFSIZE),并且不会检查其是否也包含宏名称. 仅当您使用TABLESIZE时,才会扫描其扩展以获取更多的宏名称.

Notice that BUFSIZE was not defined when TABLESIZE was defined. The ‘#define’ for TABLESIZE uses exactly the expansion you specify—in this case, BUFSIZE—and does not check to see whether it too contains macro names. Only when you use TABLESIZE is the result of its expansion scanned for more macro names.

(强调我的)

这篇关于如何在C中解析链接的宏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆