代码之家  ›  专栏  ›  技术社区  ›  fredoverflow

一条新线什么时候开始?

  •  9
  • fredoverflow  · 技术社区  · 15 年前

    我不理解以下程序的输出:

    #include <iostream>
    
    #define FOO std::cout << __LINE__ << ' ' \
                          << __LINE__ << '\n';
    int main()
    {
        FOO
    
        std::cout << __LINE__ << ' ' \
                  << __LINE__ << '\n';
    }
    

    第一个输出是 7 ,表明 FOO 是单个逻辑行,但第二个输出是 9 10 ,表示两个不同的逻辑行。为什么会有区别?

    4 回复  |  直到 10 年前
        1
  •  5
  •   Yakov Galka    15 年前

    因为

    1:  #include <iostream>
    2: 
    3:  #define FOO std::cout << __LINE__ << ' ' \
    4:                        << __LINE__ << '\n';
    5:  int main()
    6:  {
    7:      FOO // the first two __LINE__s come from here, that's one line of code
    8: 
    9:      std::cout << __LINE__ << ' ' \ // 3rd __LINE__ comes from here
    10:              << __LINE__ << '\n'; // 4th __LINE__ comes from here
    11: }
    

    __LINE__ 扩展到物理行,而不是逻辑行:

    这个 行号 在将源文件处理到当前标记时,当前源行的字符数大于翻译阶段1(2.2)中读取或引入的新行字符数。

    当线条以 \ 在翻译阶段2中连接。

    另一个唯一的逻辑实现是打印3和4以调用foo,但这似乎不是很有用。

    您还可以通过以下方式查看: _线条__ 与其他宏没有任何不同。它只是由编译器在每一行的开头自动更新的。所以代码是这样解释的:

    #include <iostream>
    
    #define __LINE__ 3
    #define FOO std::cout << __LINE__ << ' ' \
                          << __LINE__ << '\n';
    int main()
    {
    #define __LINE__ 7
        FOO
    
    #define __LINE__ 9
        std::cout << __LINE__ << ' ' \ // Yeah, you're right
    #define __LINE__ 10
                 << __LINE__ << '\n';
    }
    

    这不是有效的代码,但它演示了如何工作。应用通常的宏扩展规则,就可以得到所得到的输出。

        2
  •  3
  •   Jakob Borg    15 年前

    因为 #define 扩展包含黑客以确保 __LINE__ 是宏被“调用”的地方。否则,很多错误消息对用户没有意义。

        3
  •  2
  •   Vladimir Ivanov    15 年前

    因为你在其中定义了一个 #define 总是作为一行计算的语句。但是,第二种情况实际上是两行代码。

        4
  •  0
  •   Chubsdad    15 年前

    替换foo需要对预先定义的指令行进行评估。据我所知,这是因为,没有第二个预处理过程来评估“线”。

    因此,根据第7行的foo解释行,对\uu行进行评估。

    在预处理阶段,根据翻译单元中源代码中出现的确切行号,对代码中后续行中的uu line_uuu的用法进行了真正的评估。