我正在尝试使用预处理器技巧来声明一个魔术变量。像这样:
DECLARE(x)
应扩展为
int _DECLARED_VARIABLE_x_LINE_12
如果声明在输入源的第12行。我试图使用## token-pasting命令和__LINE__
宏,但我在那里得到一个未解释的“__LINE__
”,或者预处理器似乎完全忽略了我的行。我目前的猜测是:
#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__
答案 0 :(得分:9)
在这种情况下,通常的技巧是使用第二个宏。但是,这似乎不适用于GCC(MacOS X 10.6.4上的4.5.1),并且需要第三级宏:
#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__
#define DECLARE42(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE41(x, line) DECLARE42(x, line)
#define DECLARE40(x) DECLARE41(x, __LINE__)
int DECLARE(y);
int DECLARE40(c) = 129;
'gcc -E'的输出:
# 1 "magicvars.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "magicvars.c"
int _DECLARED_VARIABLE_y_LINE___LINE__;
int _DECLARED_VARIABLE_c_LINE_8 = 129;
我不确定我是否有一个很好的解释为什么需要第三级宏。
我也很想知道在你创建这些变量之后你将如何引用这些变量。
我经历了许多变化,然后才能找到有效的方法:
#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__
#define DECLARE11(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE10(x) DECLARE11(x, __LINE__)
#define DECLARE23(line) _LINE_ ## line
#define DECLARE22(x) _DECLARED_VARIABLE_ ## x
#define DECLARE21(x, line) DECLARE22(x) ## DECLARE23(line)
#define DECLARE20(x) DECLARE21(x, __LINE__)
#define DECLARE32(line) _LINE_ ## line
#define DECLARE31(x, line) _DECLARED_VARIABLE_ ## x ## DECLARE32(line)
#define DECLARE30(x) DECLARE31(x, __LINE__)
#define DECLARE42(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE41(x, line) DECLARE42(x, line)
#define DECLARE40(x) DECLARE41(x, __LINE__)
int DECLARE(y);
int DECLARE10(z) = 12;
int DECLARE20(a) = 37;
int DECLARE30(b) = 91;
int DECLARE40(c) = 129;
玩得开心解决为什么非工作的人无法工作。然而,他们确实指出了我的工作答案。 (我注意到Sun C编译器在同一输入上产生与GCC基本相同的结果。)
答案 1 :(得分:6)
预处理器在尝试寻找进一步的宏以进行递归替换之前,从宏替换列表中删除##
运算符。这意味着您对__LINE__
的引用会“粘贴”到宏的其余部分之前它有可能被识别为__LINE__
并替换为实际的行号。
因此,如果您想将行号嵌入宏中,除了通过宏参数传递它之外别无选择
#define DECLARE_(x, L) _DECLARED_VARIABLE_##x##_LINE_##L
#define DECLARE(x) DECLARE_(x, __LINE__)
这将正式解决原始宏定义中的直接问题。
但是,由于C / C ++预处理器规范中的另一个怪癖,这仍然无法正常工作:##
附近的参数名称被替换为相应的参数值而没有递归宏扩展参数值。即L
将替换为__LINE__
,而不会先将__LINE__
更改为实际的行号。
为了确保参数L
的递归宏扩展,需要在宏定义中引入另一个“间接层”
#define DECLARE__(x, L) _DECLARED_VARIABLE_##x##_LINE_##L
#define DECLARE_(x, L) DECLARE__(x, L)
#define DECLARE(x) DECLARE_(x, __LINE__)
在这种情况下,处理DECLARE_(x, L)
宏时,预处理器将递归处理L
:首先将其替换为__LINE__
,然后将__LINE__
替换为实际的行号。 DECLARE__
将收到完整的行号。
答案 2 :(得分:1)
如果使用“编辑并继续”,则在使用Visual Studio的调试模式下__LINE__
存在问题。 Here is a reference to it.这个问题虽然已有几年了。如果该问题得到解决,那么Jonathan Leffler's solution将正常工作。
答案 3 :(得分:0)
关于##运算符有两个特殊的扩展规则: