C预处理器中的空指令有什么作用?

8

浏览C99标准的n869草案时,我偶然发现了这个部分:

6.10.7 Null directive Semantics

A preprocessing directive of the form

# new-line

has no effect.

所以,我写了这个程序来测试它:

#
#include <stdio.h>
#

int main(void)
{
  puts("Hello, world!");

  return 0;
}

果然,gcc 对这段代码没有任何意见,即使我开启了所有警告。我意识到语言中还有其他一些不明显的结构,比如初始化器、枚举定义等允许使用额外逗号的情况,但这是有用的(例如简化代码生成器的编写)。

然而,我不明白这个结构有什么用处。有人能想到一个合理的用例或理由吗?

2个回答

3

来自GCC文档1.7节:

空指令由一个跟随换行符的 # 组成,中间只有空白字符(包括注释)。空指令被视为预处理指令,但不会对预处理器输出产生影响。空指令存在的主要意义是,输入一行只包含一个 # 的行将不会产生任何输出,而不是一个只包含 `#` 的输出行。据说一些旧的C程序包含这样的行。

记住,C预处理器是一个独立的程序,它有输入和输出。 C预处理器的输出通常包括程序注释,但如果注释出现在以“#”符号开头且除空格和注释外没有其他内容的行上,则这些注释将不会出现在预处理器输出中。 因此,空指令会导致内容存在于源代码中,但不存在于预处理器输出中。
例子:
预处理器将转换
#include <stdio.h>
#define HELLO 1
# /*This comment is for preprocessor only*/
HELLO
/*This comment is for preprocessed code*/

转换为

(... preprocessed contents of stdio.h ...)
1
/*This comment is for preprocessed code*/   

嗯,我认为它可以用来确保某个注释不会出现在预处理后的代码中。 - Michael Graczyk
这让我意识到了一个有趣但晦涩的潜在用途。如果我们使用cpp实用程序对文件进行多次遍历,例如用于代码生成,它可以用于将第一遍的注释与应出现在生成的代码中的注释分开。有一个-C标志要求cpp保留注释,但是这些空指令行上的注释仍然被丢弃。 - FatalError

3

来自GNU文档:

......null指令的主要意义在于,只包含一个#的输入行不会产生任何输出,而不是产生一个只包含#的输出行。据说一些旧的C程序包含这样的行。


我理解这意味着你可以在单独的一行上使用“#”来添加垂直空间到原始源代码,而不影响预处理器输出。也许是为了可读性? - Adam Liss
我猜是这样的。它还指出:“空指令被理解为预处理指令,但对预处理器输出没有影响。”除了可读性之外,我没有看到其他任何目的。也许,这个东西来自Unix shell脚本,就像一个注释一样。 - P.P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接