Я пишу разделяемую библиотеку C ++ для использования на C-программе. Тем не менее, у меня есть вопрос о extern
а также extern "C"
,
Рассмотрим следующий код
Мой заголовочный файл выглядит так:
#ifdef __cplusplus
extern "C" int global;
extern "C" int addnumbers(int a, int b);
#else
extern int global;
#endif
Это прекрасно работает; Я просто должен объявить
int global;
в моем .cpp или в моем .c файле. Однако я не понимаю:
В чем разница между extern "C"
а также extern
Вот? Я пытался комментировать extern "C" int global
и это работает! Зачем?
я знаю это extern "C"
используется для создания связей С Вот почему у меня extern "C" int addnumbers(int,int)
, Другими словами, если я хочу написать функцию C ++, которая должна использоваться в программе на C, я пишу extern "C"
, Теперь, что насчет глобальных переменных — я думаю, здесь другая ситуация? Я хочу, чтобы программа C использовала переменную C ++ с именем global
, но я могу использовать extern
не extern "C"
, Это почему? Это не интуитивно для меня.
Комментарий: я не думаю, что это дубликат, потому что я спрашиваю, в чем разница, когда вы используете его для переменных по сравнению с функциями.
Прикрепляя extern "C"
к своим объявлениям C ++ (как к объектам, так и к функциям) вы даете им «связь C» — делайте их доступными из кода C. Если вы пропустите эту спецификацию «языковой связи», компилятор не будет прилагать никаких усилий для правильной связи. В случае функций это приводит к неудачной связи из-за искажения. В случае глобальных переменных все может работать нормально, потому что переменные не требуют искажения.
Однако в моей системе (MS Visual Studio) связь между C и C ++ не работает, если я «забываю» указать extern "C"
спецификация связи в заголовочном файле C ++. Пример сообщения об ошибке:
error LNK2001: unresolved external symbol "int global" (?_global)
Хотя, когда я рассматриваю скомпилированный исходный код C ++, который содержит определение global
с dumpbin
Утилита, я вижу
00B 00000014 SECT4 notype External | ?global@@3HA (int global)
Таким образом, MS Visual Studio обрабатывает имена глобальных переменных, если они не имеют связи C — это делает спецификации связи C обязательными.
Кроме того, рассмотрим следующий пример:
namespace example {
int global;
}
Если глобальная переменная находится внутри пространства имен, код C не получит к ней доступ. В этом случае все компиляторы будут требовать правильной спецификации связи в объявлении C ++:
namespace example {
extern "C" int global;
}
Заключение:
использование extern "C"
когда вы хотите связать C — не имеет значения, является ли это функцией или глобальной переменной. Если это глобальная переменная, она может работать независимо, но это не гарантировано (и может быть опасно).
extern
просто сообщает компилятору, что следующая переменная (глобальная), возможно, еще не была объявлена, но она объявлена как глобальная в другой единице перевода, и на этапе компоновки символ «глобальный» будет связан с областью в памяти.
в то время как extern "C"
Это, как прокомментировали несколько человек, используется для решения проблемы искажения имени в C ++, эта функция будет называться addnumbers_i_i
(или что-то подобное) компоновщиком, а в c его символ addnumbers
«C ++ имеет специальное ключевое слово для объявления функции с привязками C: extern« C ». Функция, объявленная как extern« C », использует имя функции в качестве имени символа, так же, как функцию C. По этой причине только функции, не являющиеся членами может быть объявлено как extern «C», и они не могут быть перегружены. «
В C ++ нет стандарта для имен функций, сгенерированных компилятором. Ключевое слово extern «C» указывает компилятору генерировать имя функции в стандарте C.
Я нахожу, что extern «C» используется для компиляции функции C ++ в стандарте C, и это не относится к переменным, поскольку решения имени функции в C и C ++ различны. Например, «void foo (int x, int y)», компилятор C переведет его в «_foo», а компилятор C ++ переведет его в «_foo_int_int».