为什么链接器报告全局函数的乘法定义符号,而不是类静态方法

Why does the linker report a multiply defined symbol for global functions but not class static methods

本文关键字:符号 定义符 静态方法 定义 报告 链接 全局 函数 为什么      更新时间:2023-10-16

我知道有时链接器不会注意到在提供给链接器的所有输入(.obj 文件和静态 .lib 文件(中多次定义了符号。 当然,有时链接器确实会注意到一个符号被定义了两次并给出错误。

但在下面的代码中,链接器确实注意到全局函数定义了两次,同时没有注意到类静态方法定义了两次。 其他一切都是平等的。

这正常吗? 有解释吗? 同样,我知道链接器有时永远不会注意到第二个符号定义。 问题是全局函数和类静态方法在多次定义链接器和符号方面有什么区别。

感谢您抽出宝贵时间提供帮助。 如果我了解这里发生的事情,我会感觉更好。 下面是三个编译并链接在一起的源文件。

翻译单元1.cpp:

// First definition of GlobalFunc()
void GlobalFunc() {std::cout << "GlobalFunc() in Translation Unit 1" << std::endl;}
void GlobalFunc_TransUnit1() {GlobalFunc();}
struct Foo
{
// First definition of Foo::ClassStaticFunc()
static void ClassStaticFunc() {std::cout << "Foo::ClassStaticFunc() in Translation Unit 1" << std::endl;}
};
void ClassStaticFunc_TransUnit1() {Foo::ClassStaticFunc();}

翻译单元2.cpp:

// Second definition of GlobalFunc()
void GlobalFunc() {std::cout << "GlobalFunc() in Translation Unit 2" << std::endl;}
void GlobalFunc_TransUnit2() {GlobalFunc();}
struct Foo
{
// Second definition of Foo::ClassStaticFunc()
static void ClassStaticFunc() {std::cout << "Foo::ClassStaticFunc() in Translation Unit 2" << std::endl;}
};
void ClassStaticFunc_TransUnit2() {Foo::ClassStaticFunc();}

main.cpp - 从输出中我们可以知道哪个定义被调用

void GlobalFunc_TransUnit1();
void GlobalFunc_TransUnit2();
void ClassStaticFunc_TransUnit1();
void ClassStaticFunc_TransUnit2();
int main(int argc, char** argv)
{
// This won't link (as expected).
// The linker reports that GlobalFunc() is defined twice.
GlobalFunc_TransUnit1();
GlobalFunc_TransUnit2();
// This links despite Foo::ClassStaticFunc() being defined twice.
// In the final executable, both ClassStaticFunc_TransUnit1() and 
// ClassStaticFunc_TransUnit2() call the same Foo::ClassStaticFunc() -
// which happens to be the definition in TranslationUnit1.cpp
ClassStaticFunc_TransUnit1();  // Calls Foo::ClassStaticFunc() in TranslationUnint1.cpp
ClassStaticFunc_TransUnit2();  // Also calls Foo::ClassStaticFunc() in TranslationUnit1.cpp
}

请参阅内联说明符。由于ClassStaticFunc完全在struct定义中定义,因此它隐式是一个内联函数。允许在每个翻译单元中定义一次内联函数(而不是通常每个程序一次(。

如果这些定义不相同,则为未定义的行为。因此,通常只有一个(头(文件包含定义,然后由需要它的每个翻译单元共享。

它多次违反一个定义规则 (ODR(。 不需要诊断。 内联静态成员函数通常假定可能在多个源模块中定义(因为标头将被多次包含(,因此链接器将在任何地方只使用一个定义并忽略其余定义(因为遵守 ODR 意味着多个定义是相同的(。

但是,全局函数只应定义一次,链接器更有可能报告它们的多个定义,因为它通常指示错误。