'#' -character是否必须位于C预处理器中的一行的开头?

时间:2015-01-09 23:42:31

标签: c syntax language-lawyer c-preprocessor conditional-compilation

我已经编程了C很长一段时间了。在这段时间里,我了解到将#34;#" -character放在第一列的预处理程序指令之前是一种常见的惯例。

示例:

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO1
 #ifdef MACRO2
      puts("defined(MACRO1) && defined(MACRO2)");
 #else
      puts("defined(MACRO1)");
 #endif
 #else
      puts("!defined(MACRO1)");
 #endif
      return 0;
 }

当人们缩进他们的预处理器指令时,他们通常会这样做:

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO1
 # ifdef MACRO2
     puts("defined(MACRO1) && defined(MACRO2)");
 # else
     puts("defined(MACRO1)");
 # endif
 #else
     puts("!defined(MACRO1)");
 #endif
     return 0;
 }

我认为我从未见过有人将其格式化为:

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO1
  #ifdef MACRO2
     puts("defined(MACRO1) && defined(MACRO2)");
  #else
     puts("defined(MACRO1)");
  #endif
 #else
     puts("!defined(MACRO1)");
 #endif
     return 0;
 }

我的问题是,C语言标准是否要求# - 字符应该在第一列。

上面的第三个选项是否合法?

如果以上所有案件都合法,那么我想知道这是否合法。

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO
     puts("defined(MACRO)");
 /* Now there are other characters before the `#` */ #endif
     return 0;
 }

以下是#endif不再在&#34;开始&#34;该行,因为在路上还有其他非空白字符。

最后一个例子看起来很奇怪,Vim文本编辑器没有突出显示评论后的#endif

Screenshot

所有这些示例都是在没有任何警告的情况下使用gcc打开-Wall -pedantic标记时进行编译(包括最后一个在#endif之前发表评论的人)。

请注意,我只是对语法感到好奇。在编程时,我总是将# - 字符放在第一列,就像其他人一样。我绝不会在严肃的项目中写++i; #endif之类的东西。

2 个答案:

答案 0 :(得分:15)

在一些预标准C预处理器(意思是1989年之前)中,预处理器仅在行的开头识别#

由于C89 / C90标准要求预处理器将#识别为该行上的第一个非空白字符(并且C99和C11标准也是如此),现在缩进指令是完全合法的。甚至便携式代码在这个千年中也是如此。

在ISO / IEC 9899:2011(C11标准)中,第6.10节预处理指令说:

  

预处理指令由一系列满足以下条件的预处理令牌组成   以下约束:序列中的第一个标记是#预处理标记(at   转换阶段4)的开始是源文件中的第一个字符(可选)   在不包含换行符的白色空格之后或在空格之后   包含至少一个换行符。

翻译阶段在第5.1.1.2节翻译阶段中定义。

  
      
  1. 源文件被分解为预处理令牌7)和序列   空格字符(包括注释)。源文件不得以a结尾   部分预处理令牌或部分注释。每条评论都被替换为   一个空格字符。保留换行符。是否每个都是空的   新行以外的空白字符序列被保留或替换为   一个空格字符是实现定义的。

  2.   
  3. 执行预处理指令,扩展宏调用,以及   _Pragma一元运算符表达式被执行。如果是一个字符序列那个   匹配通用字符名称的语法由token生成   连接(6.10.3.3),行为未定义。 #include预处理。#   指令导致从阶段1处理命名的头文件或源文件   通过阶段4,递归。然后删除所有预处理指令。

  4.   

有时候,您会发现源自20世纪80年代的编码标准仍然在行开始时规定了{{1}}。

我通常不会缩进预处理程序指令,但这样做是合法的。

答案 1 :(得分:5)

不,这是C标准的引用(从第6.10节开始):

  

预处理指令由一系列令人满意的预处理令牌组成   以下约束:序列中的第一个标记是#预处理标记(at   转换阶段4)的开始是源文件中的第一个字符(可选地在包含没有换行符的空格之后)或者在空格之后   包含至少一个换行符。

所以它在文件的开头是#,或者在包含至少一个换行符的某个空格之后

这意味着:

# define foo
  # define bar

foo的定义很好,因为#是文件中的第一个标记。 bar的定义很好,因为#“跟随包含至少一个换行符的空格。”