7

Есть ли какая-то - на уровне стандарта - защита от некорректного использования объявлений extern в C? Например, пусть в одном файле есть

extern int global;

в другом -

double global = 3.1416;

Ведь mangling имен - это только в C++, который, конечно, в этой ситуации защитит (на уровне линковщика), в отличие от C, который должен скомпилировать и не поморщиться...

Получается, что в обычном C - только совесть программиста препятствие к некорректному использованию? никакого иного механизма нет (помимо вынести объявление extern в заголовочный файл и включать его во все файлы проекта)?

Harry
  • 221,325
  • Ещё есть механизм #define - #ifndef - #endif – nick_n_a Dec 12 '16 at 11:22
  • #ifndef __global_def #define __global_def double global = 3.1416; #endif – nick_n_a Dec 12 '16 at 11:27
  • @nick_n_a и чем это здесь поможет? –  Dec 12 '16 at 11:31
  • @D-side Тем что при втором заходе #ifndef отбросит "экранированый" код, будет приянто первое значение которое встретится. Если проблема в разных значениях global, то можно с помощью похожей #define конструкции выдать как warning так и error. – nick_n_a Dec 12 '16 at 11:36
  • @nick_n_a а теперь перечитайте примеры в вопросе. Проблема в том, что типы определения и объявления разные, в разных единицах трансляции. Как тут может помочь препроцессор? –  Dec 12 '16 at 11:38
  • В C++ подобная ошибка тоже вполне может быть не замечена. Надо выносить в хедер и не создавать проблем на ровном месте. – αλεχολυτ Dec 12 '16 at 13:03
  • ассоциация: http://stackoverflow.com/q/14697698/3240681 – αλεχολυτ Dec 12 '16 at 13:06
  • @alexolut Не замечена компилятором, который extern воспринял как объявление и создал эту переменную? Разве это допустимо? VC++, например, при линковке сообщил об отсутствии такой переменной - и это, по-моему, верно. Что до вынесения в заголовочный файл - как бы это сформулировать... Если аккуратно ходить, то можно и как Пети, между небоскребами по канату бегать. Но лучше проложить дорогу и поставить перила :) Недаром же в языке, например, имеется типизация, или еще какие-то вещи, не позволяющие программисту делать глупости. Хотя можно было бы просто посоветовать - не создавай проблем :) – Harry Dec 12 '16 at 13:48
  • @Harry по Стандарту плюсов - диагностика не требуется. То что VS обнаруживает проблему - хорошо. – αλεχολυτ Dec 12 '16 at 14:19
  • Защита есть - модуль, где определена переменная, не соберётся, т.к. там будут объявление "extern int" и определение "double". Можно, конечно, не включать в этот модуль соотв. заголовок... – Alexey Esaulenko Dec 12 '16 at 16:44
  • А может это так и задумано? Например, для совместимости с COMMON в фортране. – avp Dec 13 '16 at 22:10

2 Answers2

1

В принципе на практике следует поступать именно так: объявление с extern должно располагаться в заголовочном файле, а определение (с инициализатором) в некоем файле реализации включающем этот заголовочный файл. Тогда есть надежда, что такие очевидные ошибки вызовут диагностическое сообщение от компилятора.

Никакой другой "официальной" защиты в С нет.

0

Давайте начнём с того, что уясним, что данная проблема - это не проблема компилятора или конкретного языка программирования. Если модуль А компилируется сегодня в Голландии, а модуль В - через три года в Урюпинске, то НИКАКОЙ компилятор или язык программирования не сможет обеспечить проверку внешних описаний.

Далее, можно ли считать данную проблему проблемой линкера? Отчасти... Т.е. если данный конкретный формат объектного модуля ПРЕДУСМАТРИВАЕТ описание типа для каждой области внешней памяти, то линкер сможет выполнить эту проверку, если он на это запрограммирован. И вылазит две проблемы:

  1. Существуют разные форматы ОМ даже в рамках одной ОС
  2. Существуют разные линкеры даже для одного формата ОМ

Вы говорите о каких-то конкретных формате ОМ и линкере?

Если речь идёт о линкере ld из состава linux, для модулей ELF, то рекомендую посмотреть на его опцию --warn-common. Как мне кажется, она может выдать предупреждения о всех подозрительных местах.

Sergey
  • 13,474