【问题标题】:Behavior of __LINE__ when used in a macro在宏中使用时 __LINE__ 的行为
【发布时间】:2019-10-05 04:18:46
【问题描述】:

为什么__LINE__ 的计算结果会根据它是在类函数宏还是常规函数中使用而有所不同?

例如:

#include<stdio.h>

#define A() printf("%d\n",__LINE__);

int main(void) {
/* 6 */  A();
/* 7 */  A(
/* 8 */    );
/* 9 */  printf("%d\n",__LINE__
/* 10 */  );
}

我希望得到:

6
7
9

但是我们得到(使用 clang-1000.10.44.4):

6
8
9

注意在第 7 行和第 8 行的类函数宏中,使用的是最后一行,而不是第一行。

GCC 的文档很详细:https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

我为什么要关心?我正在编写一个解析器,它需要查找宏 A 的所有实例的行号,以便与 __LINE__ 将返回的内容对齐。由于需要解析可能转义的参数,因此要找到宏用法的 last 行而不是 first 行要困难得多。

【问题讨论】:

  • 最终你还是需要正确地进行解析,因为宏参数中可能存在宏以及其他复杂情况。
  • 我很惊讶地看到,输出随着上一个 gcc 版本而改变。所以:不用担心。当您更新到 gcc9.1 时,输出将匹配预期(!),请参阅 godbolt。当使用gcc -E 时,我也很惊讶地看到main 的第二行末尾没有双;;
  • @Kamil: 失踪的; 是来自godbolt 的礼物。如果您禁用过滤“仅评论行”(// 按钮),您将在两个 gcc 版本上看到分号。
  • @KamilCuk #1 godbolt 太棒了,#2 我很害怕这种行为在 gcc 9 中发生了变化。这足以让我重新考虑我的日志记录方法。

标签: c gcc c-preprocessor


【解决方案1】:

C 实现在看到关闭的) 之前不会替换A() 宏。 ) 出现在第 8 行,这就是宏替换发生的地方。

__LINE__ 关于宏替换的细节没有被 C 标准很好地指定。您可能不应该依赖这里的特定行为。当然,C 实现不能替换 A() 宏,因为它只读取到第 7 行,因为它还不知道接下来会发生什么。一旦它看到结束 ),然后,当它替换宏时,它可能会认为替换标记出现在第 7 行或第 8 行或某种混合上——C 标准对此没有具体说明;在这一点上,行号在很大程度上与 C 语义无关,__LINE__ 宏在很大程度上是为了方便调试和其他开发工作,而不是生产程序的功能(尽管它可能对它们有一些用途)。

printf 中,C 实现一看到行尾就识别__LINE__ 宏。 (其实解析比较多,输入已经被token化了,但是效果是__LINE__token在检查行尾字符的时候被识别出来了。)在第9行,所以用@代替987654331@。它是printf 的一个论点这一事实是无关紧要的。 C 实现没有进程 printf 以替换出现在第 9 行的 __LINE__ 标记;他们不互动。

【讨论】:

  • 这里的第一点很重要,但第二点是关键。该标准没有为判断观察到的行为是否比 OP 的预期行为正确或错误提供依据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 2018-05-12
  • 1970-01-01
  • 2012-05-09
相关资源
最近更新 更多