Почему компоновщик сообщает многократно определенный символ для глобальных функций, но не для статических методов класса - PullRequest
0 голосов
/ 30 июня 2018

Я знаю, что иногда компоновщик не замечает, что символ определяется несколько раз во всех входных данных, передаваемых компоновщику (файлы .obj и статические файлы .lib). И, конечно, иногда компоновщик замечает , что символ определен дважды, и выдает ошибку.

Но в приведенном ниже коде компоновщик замечает, что глобальная функция определяется дважды, и в то же время не , замечая, что статический метод класса определяется дважды. Все остальное равно.

Это нормально? Есть ли объяснение? Опять же, я понимаю, что компоновщик иногда никогда не замечает определения второго символа. Вопрос в том, в чем разница между глобальной функцией и статическим методом класса в отношении линкера и символов, определяемых несколько раз.

Спасибо, что нашли время помочь. Я бы почувствовал себя лучше, если бы понял, что здесь происходит. Вот три исходных файла, которые скомпилированы и связаны вместе.

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 - из вывода мы можем сказать, какое из определений было названо

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 ]

0 голосов
/ 30 июня 2018

См. встроенный спецификатор . Поскольку ClassStaticFunc определен полностью в определении struct, это неявно встроенная функция. Встроенная функция может быть определена один раз в каждой единице перевода (а не обычная однажды для каждой программы).

Это неопределенное поведение, если эти определения не идентичны. Следовательно, обычно есть только один (заголовочный) файл, содержащий определение, которое затем передается каждой нужной ему единице перевода.

0 голосов
/ 30 июня 2018

Это несколько раз нарушает правило единого определения (ODR). Диагностика не требуется. Обычно предполагается, что встроенные статические функции-члены потенциально определены в нескольких исходных модулях (поскольку заголовок будет включен несколько раз), поэтому компоновщик будет просто использовать одно определение везде и игнорировать остальные (поскольку выполнение ODR подразумевает, что несколько определений то же самое).

Однако глобальные функции должны быть определены только один раз, и компоновщик с большей вероятностью сообщит о нескольких их определениях, поскольку обычно это указывает на ошибку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...