首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C预处理器如何处理循环依赖关系?

C预处理器如何处理循环依赖关系?
EN

Stack Overflow用户
提问于 2014-06-12 14:08:34
回答 4查看 4.8K关注 0票数 65

我想知道C定义预处理器是如何处理循环依赖的(of #)。这是我的程序:

代码语言:javascript
复制
#define ONE TWO 
#define TWO THREE
#define THREE ONE

int main()
{
    int ONE, TWO, THREE;
    ONE = 1;
    TWO = 2;
    THREE = 3;
    printf ("ONE, TWO, THREE = %d,  %d, %d \n",ONE,  TWO, THREE);
}

下面是预处理器的输出。我不明白为什么输出是这样的。我想知道预处理器在这种情况下采取的各种步骤,以提供以下输出。

代码语言:javascript
复制
# 1 "check_macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "check_macro.c"

int main()
{
 int ONE, TWO, THREE;
 ONE = 1;
 TWO = 2;
 THREE = 3;
 printf ("ONE, TWO, THREE = %d,  %d, %d \n",ONE, TWO, THREE);
}

我在Linux3.2.0-49-generic-pae上运行这个程序,编译版本是gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-12 14:19:20

在展开预处理器宏时,该宏的名称不会展开。所以你的三个符号都被定义为它们自己:

代码语言:javascript
复制
ONE -> TWO -> THREE -> ONE (not expanded because expansion of ONE is in progress)
TWO -> THREE -> ONE -> TWO (        "                         TWO      "        )
THREE -> ONE -> TWO -> THREE (      "                         THREE    "        )

这种行为是由C标准的§6.10.3.4设置的(节编号来自C11草案,尽管据我所知,该节的措辞和编号自C89以来没有改变)。当遇到宏名称时,它将被替换为其定义(并处理###预处理器操作符,以及类似函数的宏的参数)。然后重新扫描结果以查找更多宏(在文件其余部分的上下文中):

2/如果在此替换列表扫描过程中找到要替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到要替换的宏的名称,则不会被替换为…

子句接着说,任何由于递归调用而没有被替换的标记实际上是“冻结的”:它永远不会被替换:

…这些未被替换的宏名预处理令牌不再可用于进一步替换,即使它们稍后在以其他方式替换宏名预处理令牌的上下文中被(重新)检查也是如此。

最后一句话提到的情况在实践中很少出现,但这是我能想到的最简单的情况:

代码语言:javascript
复制
#define two one,two
#define a(x) b(x)
#define b(x,y) x,y
a(two)

结果是one, twotwo在替换a时扩展为one,two,扩展后的two标记为完全扩展。随后,扩展b(one,two)。这不再是在替换two的上下文中,但是作为b的第二个参数的two已经被冻结,所以它不会再次扩展。

票数 77
EN

Stack Overflow用户

发布于 2014-06-12 14:26:40

您的问题由出版物ISO/IEC 9899:TC2第6.10.3.4节“重新扫描和进一步替换”第2段回答,为了方便您,我在此处引用;将来,如果您对规范有任何疑问,请考虑阅读规范说明。

如果在此替换列表扫描过程中找到要替换的宏的名称(不包括源文件的其余预处理标记),则不会替换该宏。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会被替换。这些未被替换的宏名预处理标记将不再可用于进一步替换,即使稍后(重新)在本应替换该宏名预处理标记的上下文中对它们进行检查也是如此。

票数 16
EN

Stack Overflow用户

发布于 2014-06-12 14:19:10

https://gcc.gnu.org/onlinedocs/cpp/Self-Referential-Macros.html#Self-Referential-Macros回答了有关自引用宏的问题。

答案的症结在于,当预处理器发现自引用宏时,它根本不会展开它们。

我怀疑,同样的逻辑也被用来防止循环定义的宏的扩展。否则,预处理器将处于无限扩展状态。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24177503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档