代码之家  ›  专栏  ›  技术社区  ›  Chris Merck

在宏中使用时_LINE__;的行为

  •  5
  • Chris Merck  · 技术社区  · 5 年前

    为什么 __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行和第7行的;8.使用最后一行,而不是第一行。

    GCC的文件中没有详细说明: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

    我为什么在乎?我正在编写一个解析器,需要找到宏的所有实例的行号 A 以这样一种方式与什么保持一致 __线__ 我会回来的。要找到正确的答案要困难得多 最后的 宏用法行,而不是 第一 因为需要分析可能转义的参数。

    1 回复  |  直到 5 年前
        1
  •  10
  •   Eric Postpischil    5 年前

    C实现并不能取代 A() 宏,直到看到结束 ) 那个 ) 出现在第8行,因此这是宏替换发生的点。

    具体的 __LINE__ 关于宏替换,C标准没有很好地规定。在这里,你可能不应该依赖某个特定的行为。当然是C语言的实现 不能 替换 A() 宏,而它只读取到第7行,因为它还不知道接下来会发生什么。一旦它看到了结束 ) 然后,当它替换宏时,它可能会考虑替换令牌将出现在第7行或第8行上,或者在某些混合上,C标准对此不明确;行号在很大程度上与C语言的语义无关,而 __线__ 宏在很大程度上是调试和其他开发工作的便利,而不是生产程序的功能(尽管它可能有一些用途)。

    printf ,C实现承认 __线__ 宏,只要它看到行的结尾。(实际上,解析更复杂;输入已标记化,但效果是 __线__ 检查行尾字符时识别标记。)它在第9行,所以被替换为 9 1.事实证明 printf 这无关紧要。C实现没有进程 printf 为了替换 __线__ 出现在第9行的标记;他们不互动。

        2
  •  1
  •   Charles G    3 年前

    在我自己进行了一些测试之后,您不能依赖于这里的行为,因为即使是gcc也会在不同版本之间改变其行为。

    #include <stdio.h>                                                                                                                                            
    #define ShowLine() printf("__LINE__ evals to %d", __LINE__);                                                                                                  
    int main()                                                                                                                                                    
    {                                                                                                                                                             
        ShowLine(                                                                                                                                                
                  );                                                                                                                                              
        return 0;                                                                                                                                                 
    }
    

    这个代码显示

    • 5与gcc 11
    • 6与gcc 7
    • 6带着叮当声13