непредсказуемое поведение встроенных функций с разными определениями - PullRequest
3 голосов
/ 08 января 2010

У меня есть следующие исходные файлы:

//test1.cpp
#include <iostream>
using namespace std;

inline void foo()
{
  cout << "test1's foo" << endl;
}

void bar();

int main(int argc, char *argv[])
{
  foo();
  bar();
}

и

//test2.cpp
#include <iostream>

using namespace std;

inline void foo()
{
    cout << "test2's foo" << endl;
}

void bar()
{
    foo();
}

Выход:

test1's foo
test1's foo

Ха ??? Итак, я должен был объявить foos статическим ... но разве такого рода вещи не должны вызывать ошибку компоновщика или хотя бы предупреждение? И как компилятор "видит" встроенные функции из разных модулей компиляции?

РЕДАКТИРОВАТЬ: Это использует gcc 4.4.1.

Ответы [ 3 ]

8 голосов
/ 08 января 2010

Вы сталкиваетесь с правилом одного определения . Вы не видите никакой ошибки, потому что:

[Некоторые] нарушения, особенно те, которые охватывают единицы перевода, диагностировать не требуется

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

Если вы действительно хотите, чтобы они отличались, вам нужна статическая функция.

5 голосов
/ 08 января 2010

R Самуэль Клатчко ответит правильно, но я отвечу частично, что он этого не сделал.

"А как компилятор" видит "встроенные функции из разных модулей компиляции?"

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

1 голос
/ 08 января 2010

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

Другой способ поместить определения в раздел COMDAT (допускается компилятором):

__declspec(selectany) int globalVariableInHeader = 42;

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

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