1
votes

I know that sometimes the linker does not notice that a symbol is defined multiple times across all the input given to the linker (.obj files and static .lib files). And of course sometimes the linker does notice that a symbol is defined twice and gives an error.

But in the code below, the linker does notice that a global function is defined twice while at the same time not noticing that a class static method is defined twice. Everything else is equal.

Is this normal? Is there an explanation? Again, I get it that the linker sometimes never notices the second symbol definition. The question is what the difference is between the global function and class static method with regard to the linker and symbols being defined multiple times.

Thanks for taking the time to help. I'd feel better if I understood what was going on here. Here are three source files that are compiled and linked together.

TranslationUnit1.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();}

TranslationUnit2.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 - from the output we can tell which of definition was called

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
}
2
If a class/struct is used in several compilation units the declaration should go in a .h file and there should be only 1 definition. This might compile, but it's not a well defined program.super
try define method outside of class. Note that classes declaration are usually in header files which re included to multiple units, and this is a reason why inclined methods are treated differently.Marek R

2 Answers

2
votes

See inline specifier. Since ClassStaticFunc is defined entirely within a struct definition, it is implicitly an inline function. An inline function is allowed to be defined once in each translation unit (rather than the usual once per program).

It is undefined behavior if these definitions are not identical. Hence, there is usually only one (header) file containing the definition, which is then shared by each translation unit that needs it.

2
votes

It violates the One Definition Rule (ODR) several times. A diagnostic is not required. Inline static member functions are generally assumed to be potentially defined in multiple source modules (since the header will be included multiple times), so the linker will just use one definition everywhere and ignore the rest (since obeying the ODR implies that the multiple definitions are the same).

Global functions, however, should only be defined once and the linker is more likely to report multiple definitions of them, since it usually indicates an error.