Две переменные с одинаковым именем и типом в двух разных файлах .c, компилируемые с помощью gcc

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

Но у меня возникло действительно странное поведение, как если бы один файл читал переменную других файлов (после их связывания). Добавление «статического» квалификатора к определениям обеих переменных, похоже, решило эту проблему.

Так что мне на самом деле интересно, что именно там произошло без квалификатора 'static'?


person Ivan Š    schedule 25.08.2011    source источник
comment
См. Также stackoverflow.com/questions/1490693/, чтобы узнать о сложных аспектах внешнего связывания.   -  person Pascal Cuoq    schedule 25.08.2011
comment
@Pascal Ваш ответ на самом деле самый полный, жаль, что я не могу отметить его как принятый. Я думал, что делаю что-то похожее на то, что вы сделали с `nm '. Единственное, что мне приходит в голову в этой ситуации, - это то, что это серьезный недостаток стандарта, о котором даже говорят здесь jetcafe.org/jim/c-style.html#need_extern. Я имею в виду, кто, черт возьми, подумал, что было бы неплохо, если бы компилятор использовал квалификатор extern ?? C ++, черт возьми, не делает таких глупых предположений.   -  person Ivan Š    schedule 27.08.2011
comment
Программирую на C более 25 лет. Никогда не использовал статику таким образом. РЖУ НЕ МОГУ. Но сегодня это решило мою проблему! Спасибо!   -  person Paul    schedule 18.08.2019


Ответы (4)


Значит, каждый файл .c должен иметь собственную переменную, верно?

Неправильный. В языке C исключение static из объявления означает неявную extern привязку.

Из C в двух словах:

Компилятор обрабатывает объявления функций без спецификатора класса хранения, как если бы они включали спецификатор extern. Точно так же любые идентификаторы объектов, которые вы объявляете вне всех функций и без спецификатора класса хранения, имеют external linkage.

person cnicutar    schedule 25.08.2011
comment
Спасибо, я этого не знал. Почему компилятор не выдал ошибку или предупреждение? - person Ivan Š; 25.08.2011
comment
Для справки: и Visual Studio 2008, и GCC 4.3.5 соблюдают это правило. И перекомпиляция кода с помощью компилятора c ++ (путем изменения расширения .cpp в VC или вызова g ++ в Linux) дает ошибку связывания нескольких определений. - person Zac; 12.02.2013

ВСЕГДА инициализируйте глобальную переменную, тогда компилятор не будет автоматически рассматривать ее привязку как внешнюю. Компилятор выдаст ошибку во время компиляции.

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

person Abraham    schedule 04.11.2014

выходной файл создается путем создания объектного файла из индивидуального файла и последующего связывания их вместе с помощью компоновщика. Теперь, когда у вас есть идентичная переменная в двух разных файлах, отдельный файл будет компилироваться без ошибок, но во время связывания компоновщик получит два определения переменной и сгенерирует ошибку. Но в случае статической области видимости обеих переменных, ограниченных для файла, все работает нормально. Я надеюсь, вы найдете это полезным.

person user2858081    schedule 01.04.2014

Насколько мне известно, когда вы не указываете ни static, ни extern, выбор компилятора. И gcc в этом случае используется для extern, поэтому в вашем случае вы должны указать static.

У меня была такая же проблема несколько лет назад :-)

person Ottavio Campana    schedule 25.08.2011