2010-03-27 6 views
5

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

Пример 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; 
}; 

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

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

ответ

3

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

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

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

Edit: Больше поиска подвернулся, что эта проблема вызвана из-за нарушения «One Definition Rule», и в результате компилятор/компоновщик не обязаны сообщать Вам о проблеме. Это делает ваш вопрос дубликатом this one.

+0

Спасибо за ответ, но здесь нет объектов библиотеки, это всего лишь мой код, смесь C и C++. Мой оригинальный вопрос остается - в чем разница между примером 1 и образцом 2 - я думал, что они должны генерировать точно такой же код? Если бы вещи были функциями вместо структур - они одно и то же, не так ли? – Jeff

+1

@ Джефф, быстрый ответ на ваш вопрос в том, что нет, эти два не то же самое, поэтому вы видите проблемы.Во втором случае вы только изменяете утверждения внутри '{}', чтобы использовать соглашения об использовании C. В первом примере вы делаете это * плюс *, указывающее, что переменные объявлены в другом месте. http://msdn.microsoft.com/en-us/library/0603949d(VS.80).aspx –

0

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

Смежные вопросы