我在 Clang 和 GCC 中发现了错误吗?

Max*_*nyk 2 c++ gcc clang++

主.cpp:

#include <iostream>

struct Cls {
    static void some_method() {
        std::cout << __FILE__ << ": " << __LINE__ << std::endl;
    }
};

extern void call_some_method();

void never_caled() {
    Cls::some_method();  // (1)
}

int main() {
    call_some_method();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

cls.cpp:

#include <iostream>

struct Cls {
    static void some_method() {
        std::cout << __FILE__ << ": " << __LINE__ << std::endl;
    }
};

void call_some_method() {
    Cls::some_method();
}
Run Code Online (Sandbox Code Playgroud)

当 (1) 被注释时, call_some_method() 将 "/home/maxim/CLionProjects/bug/cls.cpp: 5" 写入 std::cout。

当 (1) 未注释时, call_some_method() 将 "/home/maxim/CLionProjects/bug/main.cpp: 5" 写入 std::cout。

不同的输出怎么可能?

cig*_*ien 10

__FILE____LINE__是由预处理器扩展的宏。由于这些宏位于不同的文件中,并且取决于使用它们的文件,因此它们会扩展为不同的标记序列。

这意味着您的定义Cls::some_method在不同的翻译单元中是不同的。这违反了单一定义规则 ( ODR ),该规则要求在整个程序中对特定实体只有一个定义。如果有多个定义,那没问题,只要这些定义的标记序列在每个翻译单元中都是相同的,并且这些标记在解析时的含义相同。

这显然不适用于您的情况,因此您违反了 ODR,这使得程序格式错误(无需诊断)。这意味着编译器没有义务给你一个错误,但如果它确实产生了一个程序,执行该程序会调用未定义的行为 ( UB )。所以你的程序可以做任何事情,包括产生你看到的输出。

  • 从技术上讲,违反 ODR 会导致程序格式错误 (NDR)。这和 UB 之间并没有什么实际区别。 (2认同)