在宏参数中使用 #line 指令是不是合法?

Posted

技术标签:

【中文标题】在宏参数中使用 #line 指令是不是合法?【英文标题】:Is it legal to use the #line directive in a macro argument?在宏参数中使用 #line 指令是否合法? 【发布时间】:2015-02-05 12:04:10 【问题描述】:

我注意到这个程序是用 gcc 编译的:

#define X(A) A

int x = X(
#line 3 "test1.c"
        0
        );

然而,Visual Studio 编译失败:

main.cpp
main.cpp(6): error C2121: '#': invalid character: possibly the result of a macro expansion
main.cpp(6): error C2065: 'line': undeclared identifier
main.cpp(6): error C2143: syntax error: missing ';' before 'constant'
main.cpp(6): error C2059: syntax error: 'constant'

我想知道:该程序是否合法,或者它是否默默地依赖未定义(或实现定义)的行为而恰好使 gcc 接受代码?

【问题讨论】:

#line 在标准中,但可能是 Visual Studio 尝试将 "#line 3 \"test1.c\"\n0\n" 输入宏,而 GCC 评估 #在将其输入 X 之前的行 【参考方案1】:

无效。该行为是未定义的,因此不需要诊断,并且允许实现接受代码。

从 C 标准,6.10.3 宏替换:

11 [...] 如果参数列表中存在预处理标记序列,否则它们将充当预处理指令,则行为未定义。

C++ 标准在 16.3 宏替换中包含这些完全相同的词。

【讨论】:

严格来说不需要诊断,因为这一段在语义部分。例如,Constraints 部分中的显式未定义行为需要诊断,如 5.1.1.3 诊断:if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. @GrzegorzSzpetkowski 在任何地方都没有给出规则的约束,并且如果违反规则,则表示行为未定义。我认为 5.1.1.3 指的是具有单独的独立错误、一些违反约束和其他未定义行为的程序。 这真的很有意义,尤其是因为“实现定义的”行为,在约束中也从未遇到过。【参考方案2】:

如果你编译带有所有警告的示例,gcc 会给你:

警告:在宏参数中嵌入指令不可移植

clang 给你:

警告:在宏参数中嵌入指令具有未定义的行为

这绝对强烈地向我表明该行为确实是未定义的。

【讨论】:

以上是关于在宏参数中使用 #line 指令是不是合法?的主要内容,如果未能解决你的问题,请参考以下文章

UVA 12657 Boxes in a Line

在 c# 中使用 #line 指令来更改错误或警告的默认行号的原因是啥?

C语言中单井号(#)和双井号(##)在宏语句中的应用

#line 指令和实际用法

C 中的预处理器指令:使用 __LINE__ 的宏

来自 NASM 的 %line 指令等效于 MASM