2017-01-12 14 views
3

Ниже приведены два отдельных кода, записанных в двух отдельных файлах Test1.c и Test2.c. Я не использую ключевое слово extern в любом файле.Почему GCC компилирует и связывает два файла, даже если «extern» не используется?

//Test1.c 
#include <stdio.h> 

int a = 1; 
int main() 
{ 
    printf("test1 - a val = %d\n",a); 
    fn(); 
    printf("After Return : %d",a); 
} 

//Test2.c 
#include <stdio.h> 

int a; 
int fn() 
{ 
    printf("test2 - a val = %d\n",a); 
    a++; 
} 

Я составил этот код с помощью GCC:

gcc Test1.c Test2.c 

Он генерирует следующий вывод:

test1 - a val = 1 
test2 - a val = 1 

Я пытался печатать адрес переменной a в обоих кодов. Адрес также тот же.

Теперь я следующие вопросы:

  1. ли gcc автоматически компилировать и ссылку даже если extern не используется ?? Здесь, видимо, gcc внутренне делает это, поскольку я компилирую эти два файла вместе.
  2. Это поведение с/без extern ключевое слово зависит от компилятора?
+0

Это не строго соответствует C. Это «общее расширение», задокументированное в Приложении J стандарта. См. Также раздел «Не так хороший способ определить глобальные переменные» в [Как использовать «extern» для обмена переменными между исходными файлами в C?] (Http://stackoverflow.com/questions/1433204/) –

+0

Скомпилировать с '-fno-common'. –

+0

@JonathanLeffler Как это может быть дубликат этого вопроса?Мой вопрос касался поведения extern с gcc-компилятором. –

ответ

3

Этот код является неопределенным поведением без необходимости диагностики. Test1.c и Test2.c как определить объект a с внешним связыванием, что нарушает C11 6.9/5:

Если идентификатор, объявленный с внешним связыванием используется в выражении (кроме как часть операнда SizeOf или _Alignof оператор, результат которого является целочисленной константой), где-то во всей программе должно быть только одно внешнее определение для идентификатора; в противном случае должно быть не более одного.

Примечание: «внешнее определение» означает определение в области файлов. (C11 6,9/4, 6,9/5). Некоторые другие комментарии/ответы путают «внешнее определение» с «определением объекта с внешней связью» или «определение с помощью ключевого слова extern». static int x = 5; в области файлов является внешним определением.


Как упоминалось Джонатаном Леффлером в комментариях, этот конкретный результат может быть преднамеренным расширением GCC. Из С11 Приложение J.5.11 «Общие расширения»:

Может быть более одного внешнего определения для идентификатора объекта с явным использованием ключевого слова extern; если определения не согласуются или несколько инициализируются, поведение не определено.

Если gcc реализует это расширение, то это объясняет поведение, которое вы наблюдаете. Предположительно, «более одного инициализируется» в этой цитате не засчитывается неявный инициализатор, сгенерированный для пробного определения.