Единицы трансляции и компоновка

В программе C++ символ, например имя переменной или функции, можно объявить любое количество раз в область. Однако его можно определить только один раз. Это правило является правилом "Одно правило определения" (ODR). Объявление вводит (или повторно вводит) имя в программу вместе с достаточной информацией, чтобы позже связать имя с определением. Определение вводит имя и предоставляет все необходимые сведения для его создания. Если имя представляет переменную, определение явно создает хранилище и инициализирует его. Определение функции состоит из сигнатуры и тела функции. Определение класса состоит из имени класса, за которым следует блок, который перечисляет все члены класса. (Тела функций-членов могут быть определены отдельно в другом файле.)

В следующем примере показаны некоторые объявления:

int i;
int f(int x);
class C;

В следующем примере показаны некоторые определения:

int i{42};
int f(int x){ return x * i; }
class C {
public:
   void DoSomething();
};

Программа состоит из одного или нескольких единиц перевода. Единица перевода состоит из файла реализации и всех заголовков, которые он включает прямо или косвенно. Файлы реализации обычно имеют расширение .cpp файла или .cxx. Файлы заголовков .h обычно имеют расширение или .hpp. Каждая единица перевода компилируется независимо компилятором. После завершения компиляции компоновщик объединяет скомпилированные единицы перевода в одну программу. Нарушения правила ODR обычно отображаются в виде ошибок компоновщика. Ошибки компоновщика возникают, когда одно и то же имя определено в нескольких единицах перевода.

Как правило, лучший способ сделать переменную видимой в нескольких файлах — объявить ее в файле заголовка. Затем добавьте директиву #include в каждый .cpp файл, требующий объявления. Добавляя охранники вокруг содержимого заголовка, вы гарантируете, что имена заголовка объявляются только один раз для каждого урока перевода. Определите имя только в одном файле реализации.

В C++20 модули представлены в качестве улучшенной альтернативы файлам заголовков .

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

Внешняя и внутренняя компоновка

Бесплатная функция — это функция, определяемая в глобальном или пространстве имен область. Глобальные переменные, не являющиеся константными, и бесплатные функции по умолчанию имеют внешнюю связь; они видны из любой единицы перевода в программе. Ни один глобальный объект не может иметь это имя. Символ с внутренней компоновкой или связью не отображается только в единице перевода, в которой она объявлена. Если имя имеет внутреннюю компоновку, то же имя может существовать в другом модуле перевода. Переменные, объявленные в определениях классов или телах функций, не имеют связи.

Вы можете принудительно заставить глобальное имя иметь внутреннюю компоновку, явно объявив его как static. Эта ключевое слово ограничивает видимость той же единицы перевода, в которой она объявлена. В этом контексте static означает что-то другое, чем при применении к локальным переменным.

Следующие объекты имеют внутреннюю компоновку по умолчанию:

  • Объекты const
  • Объекты constexpr
  • Объекты typedef
  • staticобъекты в пространстве имен область

Чтобы предоставить const внешнюю компоновку объекта, объявите его как extern и назначьте его значение:

extern const int value = 42;

Дополнительные сведения см. в разделе extern.

См. также

Основные понятия