Это связано с тем, что называется "предварительным определением" в C. Во-первых, если вы назначите global
как в file1, так и в file2, вы получите ошибку в C. Это потому, что global
предварительно не определено в файлах file1 и file2 это уже определено.
Из стандарта С (упор мой):
Объявление идентификатора для объекта, который имеет область действия файла без инициализатора и без спецификатора класса хранения или со статическим спецификатором класса хранения, составляет предварительное определение . Если модуль перевода содержит одно или несколько предварительных определений для идентификатора, а модуль перевода не содержит внешнего определения для этого идентификатора, то поведение точно такое, как если бы модуль перевода содержал объявление области файла для этого идентификатора с составным типом как конца блока перевода, с инициализатором, равным 0.
В вашем случае, «единица перевода» (в основном) каждого исходного файла.
О «составных типах»:
Для идентификатора с внутренней или внешней связью, объявленного в области, в которой предшествующий
объявление этого идентификатора является видимым, если в предыдущем объявлении указан внутренний или
внешняя связь, тип идентификатора при последующем объявлении становится составным
типа.
Подробнее о предварительных определениях см. этот вопрос и ответы на него .
Похоже, что для вашего случая это должно быть неопределенное поведение, потому что global
определяется в конце блоков перевода, поэтому вы получаете два определения global
, и, что еще хуже, они отличаются. Похоже, компоновщик по умолчанию не жалуется на это.
GNU ld имеет опцию --warn-common
, которая предупреждает вас о нескольких предварительных определениях (общий символ - это имя компоновщика для предварительно определенных переменных):
$ gcc -Wl,--warn-common file*.c
/tmp/ccjuPGcq.o: warning: common of `global' overridden by larger common
/tmp/ccw6nFHi.o: warning: larger common is here
Из руководства :
Если для переменной есть только (один или несколько) общих символов, она помещается в область неинициализированных данных выходного файла. Компоновщик объединяет несколько общих символов для одной и той же переменной в один символ. Если они имеют разные размеры, он выбирает самый большой размер. Компоновщик превращает общий символ в объявление, если есть определение той же переменной.
Опция --warn-common
может выдавать пять видов предупреждений. Каждое предупреждение состоит из пары строк: первая описывает только что встреченный символ, а вторая описывает предыдущий символ с тем же именем. Один или оба символа будут общим символом.