extern "C" определяет, как должны именоваться символы в сгенерированном объектном файле. Если функция объявлена без внешнего «C», имя символа в объектном файле будет использовать искажение имени C ++. Вот пример.
Данный тест. С так:
void foo() { }
Компиляция и перечисление символов в объектном файле дает:
$ g++ -c test.C
$ nm test.o
0000000000000000 T _Z3foov
U __gxx_personality_v0
Функция foo фактически называется "_Z3foov". Эта строка содержит информацию о типе для возвращаемого типа и параметров, среди прочего. Если вы вместо этого напишите test.C, как это:
extern "C" {
void foo() { }
}
Затем скомпилируйте и посмотрите на символы:
$ g++ -c test.C
$ nm test.o
U __gxx_personality_v0
0000000000000000 T foo
Вы получаете связь С. Имя функции «foo» в объектном файле просто «foo», и в ней нет всей информации о причудливых типах, получаемой из искажения имени.
Обычно вы включаете заголовок в extern "C" {}, если код, который идет с ним, был скомпилирован с помощью компилятора C, но вы пытаетесь вызвать его из C ++. Когда вы делаете это, вы говорите компилятору, что все объявления в заголовке будут использовать связь Си. Когда вы связываете свой код, ваши файлы .o будут содержать ссылки на «foo», а не «_Z3fooblah», что, как мы надеемся, соответствует тому, что находится в библиотеке, с которой вы ссылаетесь.
Большинство современных библиотек устанавливают защиту вокруг таких заголовков, чтобы символы объявлялись с правильной связью. например во многих стандартных заголовках вы найдете:
#ifdef __cplusplus
extern "C" {
#endif
... declarations ...
#ifdef __cplusplus
}
#endif
Это гарантирует, что когда код C ++ включает заголовок, символы в вашем объектном файле совпадают с тем, что находится в библиотеке C. Вам следует только поместить extern "C" {} вокруг заголовка C, если он старый и у него уже нет этих охранников.