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 intenum (取决于语言)而不是宏,这显然会使用宏的当前值。 如果你真的真的需要宏,那么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更改或被删除。