没有令牌字符串的cpp扩展宏

我正在阅读CPP宏扩展,并希望在未提供(可选)令牌字符串时理解扩展。 我发现gcc v4.8.4这样做:

$ cat zz.c #define B (B) |B| $ gcc -E zz.c # 1 "zz.c" # 1 "" # 1 "" # 1 "zz.c" () | | 

任何人都可以解释为什么扩展在一个实例中是零空间而在另一个实例中是一个?

C预处理器在“令牌”上运行,只要有可能改变含义或含糊不清,它总是会添加空格以保留含义。

考虑你的例子,

 (B) 

没有歧义或含义改变()之间是否有空格而不管B的宏值如何。

但事实并非如此

 |B| 

根据宏B ,以上可能是|| 或者|something| 。 因此,预处理器被迫添加一个空格以保持C的词法规则。

任何其他可能改变含义的令牌都可以看到相同的行为。 例如,

 #define B + B+ 

会产生

 + + 

而不是

 ++ 

出于上述原因。

但是,这只是符合C词法规则的预处理器。 GCC确实拥有并支持一个名为传统处理器的旧预处理器 ,它不会添加任何额外的空格。 例如,如果以传统模式调用预处理器:

 gcc -E -traditional-cpp file.c 

然后

 #define B (B) |B| 

产生(没有空白)

 () || 

gcc -E的输出故意与C标准指定的确切规则不匹配。 C标准没有描述预处理器结果应该可见的任何特定方式,甚至不需要存在这样的方式。

只有在使用#运算符时,才需要某种预处理器输出可见。 如果你使用它,你会发现没有任何空间。

flaming.toaster的回答正确地指出gcc -E输出插入空格的原因是为了防止这两个连续的 s被解析为单个|| 令牌。 需要以下程序来诊断语法错误:

 #define EMPTY int main() { return 0 |EMPTY| 0; } 

并且空间用于确保编译器仍具有足够的信息来实际生成错误。

编辑:请参阅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 

由于它们是具有不同function的不同运算符,因此预处理器必须添加空格以避免更改语句的预期含义。