Проблема с ключевым словом extern в C ++ - PullRequest
5 голосов
/ 27 марта 2010

В чем разница между следующими двумя объявлениями? Я думал, что они были эквивалентны, но первый образец работает, а второй нет. Я имею в виду, что он компилируется и запускается, но код отображения растрового изображения отображается пустым. Я еще не прошел через это, но я упускаю что-то очевидное? GUI_BITMAP - это простая структура, описывающая растровое изображение. Это для VC ++ 2005, но я думаю, что это не так и в VC ++ 2008. Почесывая голову на этом ...

Образец 1:

extern "C" const GUI_BITMAP bmkeyA_cap_active;
extern "C" const GUI_BITMAP bmkeyA_cap_inactive;

Образец 2:

extern "C" 
{
   const GUI_BITMAP bmkeyA_cap_active;
   const GUI_BITMAP bmkeyA_cap_inactive;
};

Редактировать: Более подробное изучение показало, что второй пример создает структуры, в то время как первый относится к внешним структурам. Второй пример не должен связываться, поскольку в глобальной области видимости есть две переменные с одинаковыми именами. Но это не так, он отправляет заполненную нулями структуру в код дисплея, который сдается. Хммм .....

Редактировать 2: Выполнение того же кода через другой компилятор (IAR) фактически не удалось скомпилировать в примере 2 с ошибкой, связанной с отсутствием конструктора по умолчанию. Поэтому я предполагаю, что в ключевом слове "extern", структурах и C ++ есть что-то тонкое, чего я не понимаю. Если бы вещи во внешней области были функциями, два образца были бы идентичны, верно?

Ответы [ 2 ]

3 голосов
/ 27 марта 2010

Ваш компоновщик может молча устранить дубликаты символов за вашей спиной. Вы можете получить статические библиотеки от поставщика и связать их с вашей программой - каково решение для ситуации, когда у вас есть две такие библиотеки, и обе они определяют общий символ? Компоновщик просто разрешит это, выбрав одно или другое определение, и предоставит вам возможность справиться с последствиями. Как вы справляетесь со стадией связи вашего приложения? У вас могут быть лучшие результаты, если вы связываете файлы .o напрямую, а не помещаете их в промежуточные библиотеки перед связыванием конечного приложения.

Эта страница документации ARM хорошо описывает проблему - я ожидаю, что подобное поведение происходит в вашем случае:

Множественные определения символа в разных объектах библиотеки не обязательно обнаруживаются. Как только компоновщик нашел подходящее определение для символа, он прекращает поиск других. Если предположить, что объект, содержащий повторяющийся символ, не загружен по другим причинам, ошибки не возникнет. Это сделано намеренно и особенно полезно в некоторых ситуациях.

Редактировать: Появилось больше поисков, что эта проблема вызвана из-за нарушения " Правило одного определения ", и в результате компилятор / компоновщик не обязаны сообщать вам проблема. Это делает ваш вопрос дубликатом этого .

0 голосов
/ 27 марта 2010

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

...