我正在阅读有关CPP宏扩展的内容,并希望在未提供(可选)令牌字符串时了解扩展。我发现gcc v4.8.4这样做了:
$ cat zz.c
#define B
(B)
|B|
$ gcc -E zz.c
# 1 "zz.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "zz.c"
()
| |
任何人都可以解释为什么扩展在一个实例中是零空间而在另一个实例中是一个?
答案 0 :(得分:7)
C预处理器在“令牌”上运行,只要有可能改变含义或含糊不清,它总是会添加空格以保留含义。
考虑你的例子,
(B)
没有歧义或含义改变(
和)
之间是否有空格,无论B
的宏值如何。
但
并非如此|B|
根据宏B
,上面的内容可以是||
或|something|
。因此,预处理器被迫添加一个空格以保持C的词法规则。
对于可能改变含义的任何其他令牌,可以看到相同的行为。例如,
#define B +
B+
会产生
+ +
而不是
++
出于上述原因。
但是,这只是符合C词法规则的预处理器。 GCC确实拥有并支持一个名为 traditional的旧预处理器 处理器,不会添加任何额外的空格。例如,如果您在传统模式中调用预处理器:
gcc -E -traditional-cpp file.c
然后
#define B
(B)
|B|
产生(没有空白)
()
||
答案 1 :(得分:4)
stat_ecdf
的输出故意与C标准指定的确切规则不匹配。 C标准没有描述预处理器结果应该可见的任何特定方式,甚至不需要这样的方式。
只有在使用gcc -E
运算符时,才需要显示某种预处理器输出。如果你使用它,你可以看到没有任何空间。
flaming.toaster的回答正确地指出#
输出插入空格的原因是为了防止将两个连续的gcc -E
解析为单个|
令牌。需要以下程序来诊断语法错误:
||
并且空间用于确保编译器仍有足够的信息来实际生成错误。
答案 2 :(得分:1)
编辑:请参阅hvd关于gcc预处理程序实现的答案
这可能是区分位运算符和逻辑OR运算符。
此示例:
if (x | 4) printf("true\n"); // Bitwise OR, may or may not be true
与以下不同:
if (x || 4) printf("true\n"); // Always true
由于它们是具有不同功能的不同运算符,因此预处理器必须添加空格以避免更改语句的预期含义。