反斜杠-换行符组合如何影响 C 预处理器的 __LINE__ 宏的值?

Kur*_*ber 7 c c-preprocessor

根据 C 标准,折叠由反斜杠-换行符序列连接的多个物理行是比执行预处理器更早的转换阶段。

假设没有由于较早的#line指令引起的并发症,那么__LINE__宏的值是否反映了之前的物理行号拼接这些线?这就是您会发现的内容,例如通过手动检查源代码或文本编辑器将第 # 行报告为的内容,并且可能是更有用的替代方法。或者它是否反映了拼接之后的 # 行,这可能是预处理器在标准中实际指定的翻译阶段顺序下实际看到的?

(如果我理解正确——我很可能不会——预处理器将无法知道给定的行是否是拼接的产物。)

Eri*_*hil 4

__LINE__编译器通过以 C 标准未指定的方式记住物理行号来实现。

\n

C 2018 6.10.8.1 1 告诉我们__LINE__被替换为 \xe2\x80\x9c 当前源代码行(整型常量)的假定行号(在当前源文件内)。\xe2\x80\x9d 这个规范是模糊的,不能以有用的方式实施,同时严格遵守标准。

\n

考虑这段代码:

\n
#define Assert(test) do { if (!test) printf("Assertion on line %d failed.\\n", __LINE__); } while (0)\n\n... Many lines of code follow, including some with line splicing.\n\n    Assert(condition);\n\n... Many lines of code.\n
Run Code Online (Sandbox Code Playgroud)\n

为了有用,此代码必须打印使用的物理行号Assert。它需要是物理行号,以便用户可以在文本编辑器中找到该行,并且它需要是宏Assert被替换的行,而不是定义的行,因为这是检测到问题的地方。GCC 和 Clang 都这样做。

\n

然而,这要求在宏替换期间提供线路拼接之前的物理线路号,宏替换发生在线路拼接之后。在C 2018 5.1.1.2 1中,该标准指定了一个翻译模型,其中:

\n
    \n
  • 在第 2 阶段,\xe2\x80\x9c 后面紧跟换行符的反斜杠字符 () 的每个实例都被删除,拼接物理源代码行以形成逻辑源代码行,\xe2\x80\x9d 以及,
  • \n
  • 在第 3 阶段,\xe2\x80\x9c 源文件被分解为预处理标记和空白字符,\xe2\x80\x9d 包括换行符,但不包括在第 2 阶段删除的字符,并且,
  • \n
  • 在第 4 阶段,扩展了宏调用。
  • \n
\n

因此,如果编译器__LINE__在第 4 阶段替换宏并且实际上只有预处理标记和剩余的空白字符,则它无法知道要提供的物理行号。

\n

因此,编译器不能按照字面上的标准\xe2\x80\x99s 翻译模型来实现。为了发挥作用,它必须将物理行号与每个可能是宏名称的预处理标记相关联。每当替换宏时,它都必须传播关联的物理行号。然后,当__LINE__最终替换令牌时,编译器将用关联的物理行号来替换它。

\n