Простое написание int x;
в глобальной или локальной области означает и декларацию и определение. Как правило, объявление сообщает компилятору: «В какой-то момент эта переменная будет существовать под этим именем, поэтому вы можете использовать ее». Определение указывает компилятору на самом деле организовать создание переменной - очевидно, это может произойти только один раз.
Как правило, вы будете использовать это, добавив заголовочный файл:
// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined
extern int bar; // Declare a variable bar
#endif
И в одноместном исходном файле
#include "foo.h"
int bar; // Define bar
Если бы вы определили bar в нескольких файлах, вы бы получили ошибку; вы не можете создать переменную дважды. Но вы должны сообщать об этом компилятору в каждом исходном файле, который вы используете bar
in. Отсюда и объявление extern
.
Точная семантика определена в разделе 6.9.2 стандарта C и может быть обобщена следующим образом:
- Когда переменная объявляется в области видимости файла с инициализатором, это внешнее определение . (§6.9.2 / 1) * * 1 023
- Когда переменная объявляется в области файла без инициализатора и без спецификатора класса хранения или с указателем
static
класса хранения, это предварительное определение . Если единица перевода (файл) имеет одно или несколько предварительных определений и нет внешнего определения , компилятор автоматически добавляет истинное объявление области файла в конце единицы перевода с нулем инициализатор. (§6.9.2 / 2) * * тысяча тридцать два
Это означает, что, строго говоря, int x;
не является определением; но он автоматически создает определение тогда и только тогда, когда не имеет другого определения с инициализатором, и нет определения static
(этот третий случай - неопределенное поведение из-за разногласий в отношении связей согласно §6.2.2 / 7)
Обратите внимание, что extern int x;
не является внешним определением . Это объявление со спецификатором класса хранения extern
. Таким образом, extern int x;
само по себе не создает определение, но если у вас есть оба:
extern int x;
int x;
Тогда вы получите определение, созданное в некоторой точке файла.
С технической точки зрения это также допустимо:
extern int x;
int x;
int x = 42;
В этом случае int x;
в середине является излишним и не имеет никакого эффекта. Тем не менее, это плохая форма, так как это сбивает с толку в этом случае, когда фактическое определение.