在实现我的自己的C11编译器时,我正在尝试弄清楚如何正确处理_Pragma关键字/操作符。C11 §6.10.9将_Pragma描述为一个操作符,因此似乎可以用宏重新定义它,即#define _Pragma(x) SOME_OTHER_MACRO(x)。此外,语句#undef _Pragma应该没有效果(假设没有先前的#define _Pragma)。这类似于可以#define关键字的方式,例如旧的VC++ hack#define for if (0);else for。然而,由于_Pragma运算符在第3个翻译阶段期间进行评估,与执行预处理器指令相同,不清楚是否属于异常情况;标准未提到使用_Pragma作为宏名称是否是未定义的行为。
我使用以下代码对GCC进行了一些测试:
我使用以下代码对GCC进行了一些测试:
#define PRAGMA _Pragma
PRAGMA("message \"hi\"")
_Pragma ("message \"sup\"")
#undef PRAGMA
#undef _Pragma
//#define _Pragma(x)
_Pragma("message \"hello\"")
使用 gcc -std=c11 -pedantic -Wall -Wextra -c
编译会输出:
tmp.c:2:1: note: #pragma message: hi
PRAGMA("message \"hi\"")
^
tmp.c:4:1: note: #pragma message: sup
_Pragma ("message \"sup\"")
^
tmp.c:8:8: warning: undefining "_Pragma" [enabled by default]
#undef _Pragma
^
tmp.c:10:9: error: expected declaration specifiers or ‘...’ before string constant
_Pragma("message \"hello\"")
^
如果我添加行#undef _Alignof
,GCC不会对此抱怨。
这表明GCC通过宏实现了_Pragma
(通过警告消息),而取消定义它会导致编译错误。如果取消注释#define _Pragma(x)
,则错误会消失(因为字符串文字消失)。
所以,我的问题是:
- 实现是否允许将
_Pragma
定义为仅为宏,而不将其作为运算符实现? - 如果不允许,则GCC这样做是否有误?
- 如果
_Pragma
应该是运算符,那么将_Pragma
定义为宏是否属于未定义行为? _Pragma
的评估和其他预处理指令之间是否存在排序?或者它们具有相同的“优先级”(即按顺序评估它们)?
再次查看C11标准,并没有提到_Pragma
除了它是用于#pragma
指令的运算符。
void main(void)
讨论),但是你的研究很明显,你的问题也提出得很好。这应该会产生有趣的回复。(+1) - ryyker#ifndef _Pragma <newline>#undef _Pragma<newline>#endif
这样的代码不会引发 UB。 - Drew McGowen