C预处理器:尽早评估宏
请考虑以下设置:
啊
#define A 5 #define BA #undef A #define A 3
AC
#include "ah" #include int main() { printf("%d\n", B); return 0; }
虽然这非常合理地打印3,有没有办法让它打印5,即在第二行啊已经替换为5的A?
不,没有办法做到这一点。 除非你知道A
所有可能值,并且它们总是整数,在这种情况下你可以依次费力地测试每一个:
#if A == 0 # define B 0 #elif A == 1 # define B 1 #elif A == 2 # define B 2 /* ... and a very long etc. */ #endif
如果您的用例仅涉及整数,那么您有更多选择。 例如,您可以将B
声明为static const int
或enum
(取决于语言)而不是宏,这显然会使用宏的当前值。 如果你真的真的需要宏,那么Boost预处理库就可以实现上面#if
s的繁琐序列(有一些聪明能减少log(N)而不是N所需的预处理器语句数)。
#define
预处理器指令中没有宏替换; §6.10段中涵盖了这一事实。 C标准中的7个(C ++标准第16段第6段,措辞相同):
除非另有说明,否则预处理指令中的预处理标记不受宏扩展的影响。
在#if
和#include
指令的描述中,标准指定宏替换确实发生,这就是上面的#if
解决方案工作的原因(以及Boost实现,它也使用计算的#include
)。
是。 Boost的预处理器库(一组可移植包含,而不是扩展的预处理器)包括对“可变”宏定义的支持 。 您可以将其定义为扩展为可变槽的引用,而不是将宏定义为直接扩展为值,可以更改它,因为它可以提前将“赋值”值扩展到它。 在这种情况下,你对改变值的能力不太感兴趣,而不是这个早期扩展意味着它可以在使用B
或重新定义A
之前的某个点从A
中获取值。
#include #define A 5 #define B BOOST_PP_SLOT(1) // "assign" A to B #define BOOST_PP_VALUE A #include BOOST_PP_ASSIGN_SLOT(1) #undef A #define A 3 #include "ah" #include int main() { printf("%d\n", B); // 5 return 0; }
支持仅限于整数。 它利用了#if
指令强制扩展任何包含的宏这一事实( #line
和#error
,尽管这些对于此目的不是很有用),并使用它们为插槽构建等效的整数值分配给,存储在隐藏的后端宏中。 这样它就可以从A
“提取”一个值,然后B
可以引用值本身,即使A
更改或被删除。