Из стандарта C (6.9.2 Определения внешних объектов)
1 Если объявление идентификатора для объекта имеет файловую область и инициализатор, объявление является внешним определением идентификатора.
и
2 Объявление идентификатора для объекта, имеющего область действия файла без инициализатора, без спецификатора класса хранения или со статическим спецификатором класса хранения, составляет предварительное определение. Если единица трансляции содержит одно или несколько предварительных определений для идентификатора, а единица трансляции не содержит внешнего определения для этого идентификатора, то поведение будет таким же, как если бы единица трансляции содержала объявление области файла этого идентификатора с составным типом как конца единицы трансляции с инициализатором, равным 0.
И есть пример в стандарте C
int i1 = 1; // definition, external linkage
//...
int i1; // valid tentative definition, refers to previous
Итак, в вашей программе это одно объявление
int a = 3;
внешнее определение идентификатора a
и этот
int a;
это предварительное определение, которое относится к предыдущему внешнему определению идентификатора.
Если использовать инициализатор во втором объявлении, вы получите два внешних определения для идентификатора, и компилятор выдаст ошибку, потому что может существовать только одно внешнее определение.
Учтите, что C и C ++ различаются по отношению к этому контексту,
Из стандарта C ++ (C.1.2, пункт 6: основные концепции)
6.1
Изменение: C ++ не имеет «предварительных определений», как в C. Например, в области видимости файла,
int i;
int i;
допустимо в C, недопустимо в C ++.
person
Vlad from Moscow
schedule
14.11.2017
extern
. - person Ctx   schedule 14.11.2017extern
, это будет означать, чтоint a; ... int a;
будет эквивалентноextern int a; ... extern int a;
, но последний не связывает. - person Jabberwocky   schedule 14.11.2017