В языке Си++, при компиляции исходного кода в объектный *.o-файл, происходит так называемый name mangling. В русскоязычной литературе этот процесс называется "декодирование имен".
Суть в том, что из-за возможности перегрузки имен функций (когда в языке в одном пространстве имен допустимо существование функций с одинаковыми именами но разными типами аргументов), в Си++ возникает проблема записи таких пересекающихся имен функций в объектнике. Чтобы ее решить, был придуман следующий механизм переименования функций, именуемый манглингом:
- В начале имени функции пишется префикс "_Z". Он говорит о том, что это имя прошло через процедуру name mangling.
- Далее указывается десятичное число, которое означает длину оригинального названия функции в символах.
- Далее пишется само оригинальное имя функции.
- Далее пристыковываются символы, обозначающие типы всех аргументов функции, слева-направо.
Вот пример.
Функция имеет прототип:
double summ(double x, int y)
Тогда после процедуры манглинга, функция будет называться:
_Z4summdi
Здесь:
- "_Z" - это mangle-префикс,
- "4" - длинна оригинального имени,
- "summ" - само оригинальное имя,
- "d" - тип double первого аргумента,
- "i" - тип int второго аргумента.
Кстати, в языке Си такой проблемы нет - там нет перегрузки функций, и поэтому имя функции просто хранится "как есть". И в этом кроется проблема: невозможно просто так взять, и использовать объектник и заголовок от библиотеки Си в проекте на Cи++. Потому что при обращении к любой функции, в том числе и к функции summ(), компилятор Си++ будет производить name mangling. И естественно, при линковке программы, измененное манглингом имя просто не будет найдено в Си-шном объектнике.
Для того, чтобы в Си++ можно было вызвать функцию из объектника, написанного и скомпилированного на языке Си, используется конструкция extern "C". Пишется она так:
extern "C"
{
double summ(double x, int y)
}
Все функции, прототипы которых написаны внутри блока extern "C", будут вызываеться без использования name mangling.
Иногда имеет смысл заключать в extern "C" не просто прототипы функций, а само подключение заголовочного файла, который идет вместе с Си-шным объектником. Делается это так:
extern "C"
{
#include "our_math.h"
}
Тогда все прототипы, написанные внутри файла-заголовка, будут линковаться без использования name mangling.
Иногда авторы Си-шных библиотек учитывают, что их библиотека может использоваться как в составе Си-шного проекта, так и в составие Си++ кода. Для этого они в заголовочном файле сами пишут директиву extern "C", обрамляя ее конструкциями условной компиляции:
#ifdef __cplusplus
extern "C"
{
#endif
double summ(double x, int y)
#ifdef __cplusplus
}
#endif
В этом случае, в Си++ коде использовать конструкцию extern "C" не имеет смысла, линковка будет работать и без нее.