没有标记字符串的宏的 cpp 扩展

cpp expansion of macro with no token-string

我正在阅读 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"

()
| |

谁能解释为什么扩展在一个实例中是零空间而在另一个实例中是零空间?

编辑:查看 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

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

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

唯一需要某种预处理器输出可见的情况是在使用 # 运算符时。如果你使用它,你会发现没有 space.

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

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

和 space 是为了确保编译器仍然有足够的信息来实际生成错误。

C 预处理器在 "tokens" 上运行,每当有可能改变含义或歧义时,它总是添加白色 space 以保留含义。

考虑你的例子,

(B)

无论 B.[=24= 的宏值如何,在 () 之间添加或不添加 space 都没有歧义或意义改变]

却不是这样
|B|

根据宏 B,以上可能是 |||something|。所以预处理器被迫添加一个白色space以保持C的词法规则。

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

#define B +
B+

会产生

+ +

相对于

++

出于上述原因。

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

gcc -E -traditional-cpp file.c

然后

#define B 

(B)
|B|

生产(没有白色space)

()
||