wef*_*fa3 9 c syntax conditional-compilation language-lawyer c-preprocessor
我已经编程了C很长一段时间了.在这段时间里,我了解到在第一列放置预处理程序指令之前的"#"字符是一种常见的约定.
例:
#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;
}
Run Code Online (Sandbox Code Playgroud)
当人们缩进他们的预处理器指令时,他们通常会这样做:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我不认为我曾见过有人像这样格式化:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果C语言标准要求#
-character应该在第一列.
那么上面的第三个选择是否合法?
如果以上所有案件都合法,那么我想知道这是否合法.
#include <stdio.h>
int main(void) {
#ifdef MACRO
puts("defined(MACRO)");
/* Now there are other characters before the `#` */ #endif
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里#endif
不再是该行的"开始",因为路上还有其他非空白字符.
关于最后一个例子看起来很奇怪的是Vim
文本编辑器没有突出显示#endif
评论之后的内容.
所有这些例子我已没有使用任何警告编译gcc
与-Wall -pedantic
开启标志(包括最后一个与评论之前#endif
).
请注意,我只是对语法感到好奇.#
在编程时,我总是像其他人一样把字符放在第一列.我永远不会++i; #endif
在严肃的项目中写出类似的东西.
Jon*_*ler 15
在一些预标准C预处理器(意思是1989年之前)中,预处理器仅#
在行的开头识别.
由于C89/C90标准要求预处理器#
将线路识别为第一个非空白字符(并且C99和C11标准也是如此),现在缩进指令是完全合法的,它甚至可以实现这个千年的所有这一切都是可移植的代码.
在ISO/IEC 9899:2011(C11标准)中,第6.10节预处理指令说:
甲预处理指令由满足以下约束预处理标记的序列组成:所述序列中的第一令牌是
#
预处理令牌(在翻译阶段4的开始)是源文件(可选地后空白空间中的第一个字符不包含换行符或在包含至少一个换行符的空格后面.
翻译阶段在5.1.1.2翻译阶段中定义.
源文件被分解为预处理标记7)和空白字符序列(包括注释).源文件不应以部分预处理标记或部分注释结束.每个注释都被一个空格字符替换.保留换行符.是否保留或替换为新行以外的每个非空白字符序列是由实现定义的.
执行预处理指令,扩展宏调用,并执行_Pragma一元运算符表达式.如果通过标记连接(6.10.3.3)生成与通用字符名称的语法匹配的字符序列,则行为未定义.甲
#include
预处理指令导致从第1阶段至第4阶段处理指定的头或源文件,递归.然后删除所有预处理指令.
偶尔,您会发现源自20世纪80年代的编码标准仍然规定" #
在线路开始".
我通常不会缩进预处理程序指令,但这样做是合法的.
不,这是C标准的引用(从第6.10节开始):
预处理指令由一系列满足以下约束的预处理令牌组成:序列中的第一个令牌是一个
#
预处理令牌(在转换阶段4的开始处)是源文件中的第一个字符(可选地在空格之后)不包含换行符或在包含至少一个换行符的空格后面.
所以它是#
在文件的开头或者在包含至少一个换行符的一些空格之后.
这意味着:
# define foo
# define bar
Run Code Online (Sandbox Code Playgroud)
foo
的定义很好,因为它#
是文件中的第一个标记.bar
的定义很好,因为#
"跟随包含至少一个换行符的空格."