考虑以下设置:
A.H
#define A 5
#define B A
#undef A
#define A 3
交流转换器
#include "a.h"
#include <stdio.h>
int main()
{
printf("%d\n", B);
return 0;
}
虽然这非常合理地打印3,但有没有办法让它打印5,即在a.h的第2行已经用5代替A?
答案 0 :(得分:14)
不,没有办法做到这一点。除非你知道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
的{{1}}的繁琐序列(有一些聪明的东西可以减少记录所需的预处理器语句数量(N)而不是N )。
#define
预处理程序指令中没有宏替换; §6.10段中涵盖了这一事实。 C标准中的第7条(C ++标准第16条第6款,措辞相同):
除非另有说明,否则预处理指令中的预处理标记不受宏扩展的影响。
在#if
和#include
指令的描述中,标准指定宏替换确实发生,这就是上面#if
解决方案有效的原因(以及Boost实现,也是使用计算的#include
)。
答案 1 :(得分:7)
是。 Boost的预处理器库(一组可移植包含,而不是扩展的预处理器)包括support for "mutable" macro definitions。您可以将其定义为扩展为可变槽的引用,而不是将宏定义为直接扩展为值,可以更改它,因为它可以提前将“赋值”值扩展到它。在这种情况下,你对改变价值的能力不太感兴趣,而不是这个早期扩展意味着它可以在使用{{1}之前的某个时刻从A
中获取值的事实。 }或重新定义B
。
A
支持仅限于整数。它充分利用了#include <boost/preprocessor/slot/slot.hpp>
#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 "a.h"
#include <stdio.h>
int main()
{
printf("%d\n", B); // 5
return 0;
}
指令强制扩展任何包含的宏这一事实(#if
和#line
也是如此,尽管这些对于此目的并不是非常有用),并使用它们来构建为分配给的插槽提供等效整数值,存储在隐藏的后端宏中。通过这种方式,它可以从#error
“提取”值,然后A
即使B
发生更改或被删除,也可以引用该值。