Байланысты: Бьерн Страуструп. Язык программирования С . М Бином, 2011
4.4 Связывание с программами на других языках Программы на С++ часто содержат части, написанные на других языках, и наоборот, часто фрагмент на
С++ используется в программах, написанных на других языках. Собрать в одну программу фрагменты,
написанные на разных языках, или, написанные на одном языке, но в системах программирования с
разными соглашениями о связывании, достаточно трудно. Например, разные языки или разные
реализации одного языка могут различаться использованием регистров при передаче параметров,
порядком размещения параметров в стеке, упаковкой таких встроенных типов, как целые или строки,
форматом имен функций, которые транслятор передает редактору связей, объемом контроля типов,
который требуется от редактора связей. Чтобы упростить задачу, можно в описании внешних указать
условие связывания. Например, следующее описание объявляет strcpy внешней функцией и указывает,
что она должна связываться согласно порядку связывания в С:
extern "C" char* strcpy(char*, const char*);
Результат этого описания отличается от результата обычного описания
extern char* strcpy(char*, const char*);
только порядком связывания для вызывающих strcpy() функций. Сама семантика вызова и, в частности,
контроль фактических параметров будут одинаковы в обоих случаях. Описание extern "C" имеет смысл
использовать еще и потому, что языки С и С++, как и их реализации, близки друг другу. Отметим, что в
описании extern "C" упоминание С относится к порядку связывания, а не к языку, и часто такое описание
используют для связи с Фортраном или ассемблером. Эти языки в определенной степени подчиняются
порядку связывания для С.
Утомительно добавлять "C" ко многим описаниям внешних, и есть возможность указать такую
спецификацию сразу для группы описаний. Например:
extern "C" {
char* strcpy(char*, const char);
int strcmp(const char*, const char*)
int strlen(const char*)
Бьерн Страуструп.
Язык программирования С++
105
//
...
}
В такую конструкцию можно включить весь заголовочный файл С, чтобы указать, что он подчиняется
связыванию для С++, например:
extern "C" {
#include
}
Обычно с помощью такого приема из стандартного заголовочного файла для С получают такой файл
для С++. Возможно иное решение с помощью условной трансляции:
#ifdef __cplusplus
extern "C" {
#endif
char* strcpy(char*, const char*);
int strcmp(const char*, const char*);
int strlen(const char*);
// ...
#ifdef __cplusplus
}
#endif
Предопределенное макроопределение __cplusplus нужно, чтобы обойти конструкцию extern "C" { ...},
если заголовочный файл используется для С.
Поскольку конструкция extern "C" { ... } влияет только на порядок связывания, в ней может содержаться
любое описание, например:
extern "C" {
// произвольные описания
//
например:
static int st;
int
glob;
}
Никак не меняется класс памяти и область видимости описываемых объектов, поэтому по-прежнему st
подчиняется внутреннему связыванию, а glob остается глобальной переменной.
Укажем еще раз, что описание extern "C" влияет только на порядок связывания и не влияет на порядок
вызова функции. В частности, функция, описанная как extern "C", все равно подчиняется правилам
контроля типов и преобразования фактических параметров, которые в C++ строже, чем в С. Например:
extern "C" int f();
int g()
{
return f(1); // ошибка: параметров быть не должно
}