gpt4 book ai didi

c - 如果 GCC 错误 _Pragma 出现在中间预处理步骤中,它会触发吗?

转载 作者:太空宇宙 更新时间:2023-11-03 23:41:41 24 4
gpt4 key购买 nike

如果使用 gcc -E 进行预处理,以下代码会从 _Pragma("GCC error") 中产生一些错误:

_Pragma("GCC error \"ERROR\"") // error

#define MACRO_ERROR _Pragma("GCC error \"MACRO_ERROR\"")
MACRO_ERROR // error

#define VOID(arg)
VOID(_Pragma("GCC error \"VOID_ERROR\"")) // no error

#define MACRO_VOID_ERROR VOID(_Pragma("GCC error \"MACRO_VOID_ERROR\""))
MACRO_VOID_ERROR // no error

#define FORWARD(macro, arg) macro(arg)
FORWARD(VOID, _Pragma("GCC error \"FORWARD_VOID_ERROR\"")) // error

#define MACRO_FORWARD_VOID_ERROR FORWARD(VOID, _Pragma("GCC error \"MACRO_FORWARD_VOID_ERROR\""))
MACRO_FORWARD_VOID_ERROR // error

FORWARD(VOID, _Pragma("GCC error\"FORWARD_VOID_ERROR\""))MACRO_FORWARD_VOID_ERROR 产生错误,尽管 pragma 运算符不是 在最后的扩展中(它是空的)。

这是预期的行为吗?

相比之下,VOID(_Pragma("GCC error\"VOID_ERROR\""))MACRO_VOID_ERROR 不会产生错误。这似乎是因为 pragma 运算符被这些“预处理得足够快”。

这背后的规则是什么?

以前,我假设 pragma 运算符如果仅出现在中间扩展步骤中则不会产生任何影响。显然这是错误的,至少对于我的 gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

gcc -E 的输出(删除空行):

# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "<stdin>"
# 1 "<stdin>"
<stdin>:1:11: error: ERROR
# 1 "<stdin>"
# 4 "<stdin>"
<stdin>:4:11: error: MACRO_ERROR
# 4 "<stdin>"
# 13 "<stdin>"
<stdin>:13:11: error: FORWARD_VOID_ERROR
# 13 "<stdin>"
# 16 "<stdin>"
<stdin>:16:11: error: MACRO_FORWARD_VOID_ERROR
# 16 "<stdin>"

最佳答案

这实际上是预期的(或者至少是我所预期的),尽管它不直观,因为您将表达式级别的副作用混合到一种最初设计为完全无副作用且部分惰性的语言中.

引用 C 标准而不是 GCC 的文档,我们可以在 6.10.3.1 中找到以下内容:

A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

这里措辞不明确的关键部分是,标准只说参数在被替换之前被扩展(“好像它构成了文件的其余部分”)。它没有明确指出,如果一个论点根本不会被替换,就需要对其进行扩展,并且由于该段的第一部分清楚地表明,如何处理一个论点取决于它实际所处的上下文由宏使用,这是一个合理的优化(对于处理像 Boost 这样的复杂元编程库也是非常必要的)。

“就好像它们构成了文件的其余部分”是为什么 _Pragma 运算符的执行应该在替换为参数之前发生的关键:5.1.1.2_Pragma 执行列为与宏替换属于同一阶段,因此如果替换应用于给定的标记序列,当参数替换时肯定是这样,_Pragma 执行。

因此 _Pragma 应该在 FORWARD 情况下运行是完全不足为奇的,因为它需要在 之前两步进行评估和应用效果>VOID 宏在重新扫描期间被拾取以进行扩展。在直接调用 VOID 的情况下是否应该应用它可能是模棱两可的,但是由于标准明确地让宏根据参数的使用方式决定如何处理参数,因此有道理应该允许完全使用的参数永远不会被评估,即使没有直接指定也是如此。

关于c - 如果 GCC 错误 _Pragma 出现在中间预处理步骤中,它会触发吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43887279/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com