Ric*_*III 10 c macros gcc clang c-preprocessor
我正在玩C预处理器,当看起来如此简单的事情失败时:
#define STR_START "
#define STR_END "
int puts(const char *);
int main() {
puts(STR_START hello world STR_END);
}
Run Code Online (Sandbox Code Playgroud)
当我用gcc编译它时(注意:与clang类似的错误),它失败了,出现这些错误:
$ gcc test.c test.c:1:19: warning: missing terminating " character test.c:2:17: warning: missing terminating " character test.c: In function ‘main’: test.c:7: error: missing terminating " character test.c:7: error: ‘hello’ undeclared (first use in this function) test.c:7: error: (Each undeclared identifier is reported only once test.c:7: error: for each function it appears in.) test.c:7: error: expected ‘)’ before ‘world’ test.c:7: error: missing terminating " character
哪种困惑我,所以我通过预处理器运行它:
$ gcc -E test.c
# 1 "test.c"
# 1 ""
# 1 ""
# 1 "test.c"
test.c:1:19: warning: missing terminating " character
test.c:2:17: warning: missing terminating " character
int puts(const char *);
int main() {
puts(" hello world ");
}
尽管有警告,但产生完全有效的代码(在粗体文本中)!
如果,C中的宏只是文本替换,为什么我的初始示例会失败?这是编译器错误吗?如果没有,标准中的哪个部分有关于这种情况的信息?
注意:我不是在寻找如何使我的初始片段编译.我只是在寻找有关此方案失败原因的信息.
Joh*_*ode 10
问题是,即使代码扩展为" hello, world ",预处理器也不会将其识别为单个字符串文字标记; 相反,它被识别为(无效)序列令牌",hello,,,world,".
6.4词汇元素
...
3 令牌是翻译阶段7和8中语言的最小词汇元素.令牌的类别是:关键词,标识符,常量,字符串文字和标点符号.预处理标记是翻译阶段3到6中语言的最小词汇元素.预处理标记的类别是:标题名称,标识符,预处理数字,字符常量,字符串文字,标点符号和单个非空白字符不要在词法上匹配其他预处理令牌类别.69) 如果一个'或一个"字符与最后一个类别匹配,则该行为未定义.预处理令牌可以用空格分隔; 这包括注释(稍后描述)或空白字符(空格,水平制表符,换行符,垂直制表符和换页符)或两者.如6.10中所述,在翻译阶段4期间的某些情况下,空白区域(或其缺失)不仅仅用于预处理标记分离.空格可能仅作为标题名称的一部分出现在预处理标记内,或出现在字符常量或字符串文字中的引号字符之间.
69)在翻译阶段4内部使用了一个附加类别的地方标记(见6.10.3.3); 它不会出现在源文件中.
请注意,在此定义下既不是'也不"是标点符号.