我正在尝试使用预处理器技巧声明一个神奇变量。类似于这样:
DECLARE(x)
应该扩展为:
int _DECLARED_VARIABLE_x_LINE_12
如果声明在输入源的第12行,我试图使用##令牌粘贴命令和__LINE__
宏,但是要么在那里得到一个未解释的"__LINE__
",要么预处理器似乎完全忽略了我的行。我目前的猜测是:
#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__
我正在尝试使用预处理器技巧声明一个神奇变量。类似于这样:
DECLARE(x)
int _DECLARED_VARIABLE_x_LINE_12
如果声明在输入源的第12行,我试图使用##令牌粘贴命令和__LINE__
宏,但是要么在那里得到一个未解释的"__LINE__
",要么预处理器似乎完全忽略了我的行。我目前的猜测是:
#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__
#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基本相同的结果。)
##
运算符。这意味着在将__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__
将接收完整的行号。如果您正在使用编辑并继续功能,那么在 Visual Studio 的调试模式下,__LINE__
可能会出现问题。这里有一个相关的参考链接。 不过这个问题已经存在几年了。如果该问题已得到解决,则Jonathan Leffler的解决方案将可以正常工作。
关于 ## 运算符,有两个特殊的扩展规则: