_Pragma和宏替换

时间:2014-07-23 16:18:21

标签: c macros undefined-behavior

在实现我自己的C11编译器时,我试图弄清楚如何处理_Pragma关键字/运算符。 C11§6.10.9将_Pragma描述为运算符,因此似乎可以用宏重新定义它,即#define _Pragma(x) SOME_OTHER_MACRO(x)。此外,声明#undef _Pragma应该没有效果(假设#define之前没有_Pragma。这类似于关键字#define d的方式,例如旧的VC ++ hack #define for if (0) ; else for。但是,因为在转换阶段3期间评估_Pragma运算符,与执行预处理程序指令的阶段相同,所以不清楚这是否是异常;该标准未提及使用_Pragma作为宏名称的未定义行为。

我使用以下代码对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),则错误消失(因为字符串文字消失)。

所以,我的问题是:

  1. 是否允许实现将_Pragma定义为宏,而不是将其实现为运算符?
  2. 如果没有,GCC是否会这样做错误?
  3. 如果_Pragma应该是一个运算符,那么将_Pragma定义为宏是未定义的行为吗?
  4. _Pragma评估与其他预处理程序指令之间是否有任何顺序?或者它们是否具有相同的“优先级”(即它们是按顺序评估的)?
  5. 再次,通过C11标准,除了它是一个可以用于_Pragma指令的运算符之外,没有提及#pragma的任何内容。

1 个答案:

答案 0 :(得分:5)

不需要禁止_Pragma成为宏名称的特殊规则。拥有前导下划线和大写字母,无论如何,它都是您不应该使用的保留标识符。使用保留标识符会导致程序的未定义行为,编译器可能会执行任何操作。

一个实现可以将它实现为一个宏,但是只要你正确使用它,这对你来说应该是透明的,只要你不惹它。实现必须保证的唯一重要的事情是" destringization"和#34;标记化" _Pragma的参数的完成就像在第3阶段一样(如果它是#34;只有"一个宏很难),并且在第4阶段处理得到的#pragma指令