c - _Pragma 和宏替换

标签 c macros undefined-behavior

在实现我自己的 C11 编译器时,我试图弄清楚如何准确处理 _Pragma 关键字/运算符。 C11 §6.10.9 将 _Pragma 描述为运算符,因此似乎可以使用宏重新定义它,即 #define _Pragma(x) SOME_OTHER_MACRO(x)。此外,语句 #undef _Pragma 应该没有效果(假设 _Pragma 之前没有 #define)。这类似于关键字可以被 #defined 的方式,例如旧的 VC++ hack #define for if (0) ;否则为。但是,因为 _Pragma 运算符是在翻译阶段 3 中求值的,与执行预处理器指令的阶段相同,所以不清楚这是否是一个异常;该标准没有提及使用 _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 评估和其他预处理器指令之间是否有任何顺序?或者它们是否具有相同的“优先级”(即它们按顺序评估)?

同样,查看 C11 标准没有提及任何关于 _Pragma 的内容,除了它是一个可用于 #pragma 指令的运算符。

最佳答案

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

一个实现可以将它实现为一个宏,但这对您来说应该是透明的,只要您正确使用它,只要您不乱用它。实现必须保证的唯一重要的事情是 _Pragma 的参数的“去字符串化”和“tokeninzation”就像在阶段 3 中一样完成(如果它“只是”宏),并且生成的 #pragma 指令在阶段 4 中处理。

关于c - _Pragma 和宏替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24915787/

相关文章:

c++ - 是否允许 null terminate() 处理程序?

c++ - 此 C++ 代码是否会产生未定义的行为?

c - _mm256_store_ps() 函数是原子的吗?与 openmp 一起使用时

c - 希腊字符串的长度大于应有的长度

vbscript - 将 VBScript 的返回值读入 SAS

rust - `&T as *const T as *mut T` 是 `static mut` 项目的声音吗?

mysql - 意外的函数调用

c++ - 检查数字是否在范围内时 unsigned int 的翻转问题

macros - 调用rust宏时 `error: expected open delimiter`是什么意思?

c++ - 宏作为预处理器指令的参数