Spec-Zone.ru › C

Внешние и предварительные определения

На верхнем уровне единицы трансляции (то есть исходного файла со всеми #includes после препроцессора) каждая C-программа представляет собой последовательность объявлений, которые объявляют функции и объекты с внешней или внутренней связью. Эти объявления известны как внешние объявления, потому что они появляются вне любой функции.

extern int n; // external declaration with external linkage
int b = 1;    // external definition with external linkage
static const char *c = "abc"; // external definition with internal linkage
int f(void) {  // external definition with external linkage
    int a = 1; // non-external
    return b; 
}
static void x(void) { // external definition with internal linkage
}

Объекты, объявленные с внешним объявлением, имеют статическую продолжительность хранения, и поэтому не могут использовать auto или register спецификаторы за исключением того, что auto может использоваться для вывода типа(с C23). Идентификаторы, введённые внешними объявлениями, имеют объём файла.

Предварительные определения

Предварительное определение — это внешнее объявление без инициализатора и либо без спецификатора класса хранения, либо со спецификатором static.

Предварительное определение — это объявление, которое может или не может действовать как определение. Если фактическое внешнее определение найдено ранее или позже в той же единице трансляции, то предварительное определение действует только как объявление.

int i1 = 1;     // definition, external linkage
int i1;         // tentative definition, acts as declaration because i1 is defined
extern int i1;  // declaration, refers to the earlier definition
 
extern int i2 = 3; // definition, external linkage
int i2;            // tentative definition, acts as declaration because i2 is defined
extern int i2;     // declaration, refers to the external linkage definition

Если определений в той же единице трансляции нет, то предварительное определение действует как фактическое определение, которое пусто инициализирует объект.

int i3;        // tentative definition, external linkage
int i3;        // tentative definition, external linkage
extern int i3; // declaration, external linkage
// in this translation unit, i3 is defined as if by "int i3 = 0;"

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

static int i4 = 2; // definition, internal linkage
int i4;            // Undefined behavior: linkage disagreement with previous line
extern int i4;     // declaration, refers to the internal linkage definition
 
static int i5; // tentative definition, internal linkage
int i5;        // Undefined behavior: linkage disagreement with previous line
extern int i5; // refers to previous, whose linkage is internal

Предварительное определение с внутренней связью должно иметь полный тип.

static int i[]; // Error, incomplete type in a static tentative definition
int i[]; // OK, equivalent to int i[1] = {0}; unless redeclared later in this file

Правило одного определения

Каждая единица трансляции может иметь ноль или одно внешнее определение каждого идентификатора с внутренней связью (глобальная переменная с static).

Если идентификатор с внутренней связью используется в любом выражении, кроме не-VLA,(с C99) sizeof, _Alignof(с C11), или typeof(с C23), в единице трансляции должно быть одно и только одно внешнее определение для этого идентификатора.

Вся программа может иметь ноль или одно внешнее определение каждого идентификатора с внешней связью.

Если идентификатор с внешней связью используется в любом выражении, кроме не-VLA,(с C99) sizeof, _Alignof(с C11), или typeof(с C23), то где-то во всей программе должно быть одно и только одно внешнее определение для этого идентификатора.

Примечания

Встроенные определения в разных единицах трансляции не ограничены правилом одного определения. Подробности о встроенных определениях функций см. в inline.

(с C99)

См. продолжительность хранения и связь для значения ключевого слова extern при объявлениях в области файла

См. определения для различий между объявлениями и определениями.

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

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.9 Внешние определения (с. 113-116)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.9 Внешние определения (с. 155-159)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.9 Внешние определения (с. 140-144)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.7 ВНЕШНИЕ ОПРЕДЕЛЕНИЯ

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/extern

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API