Последнее обновление:2026-10-12
C++ спецификация компоновки extern¶
Об авторе:¶
Личный официальный аккаунт:

1.Различия компиляции C++ и C¶
В C++ часто можно встретить в заголовочных файлах функции, модифицированные extern "C" — зачем это нужно? Это нужно, чтобы код C++ линковался с функциями, определёнными в модулях на языке C.
Хотя C++ совместим с C, символы, генерируемые при компиляции функций в файлах C++, отличаются от генерируемых в C. Поскольку C++ поддерживает перегрузку функций, символы, создаваемые компилятором C++, содержат информацию о типах параметров функции, а в C — нет.
Например, после того как функция int add(int a, int b) обработана компилятором C++ и получен .o-файл, add превращается во что-то вроде add_int_int, тогда как в C это будет что-то вроде _add; иначе говоря: одна и та же функция после компиляции в C и C++ даёт разные символы.
Отсюда возникает проблема: если в C++ используются функции, реализованные на C, при компиляции и линковке произойдёт ошибка — будет сообщено, что соответствующий символ не найден. Вот здесь и пригождается extern "C": он сообщает компоновщику, что нужно искать C-символы вида _add, а не символы, промодифицированные C++.
2.Вызов C-функций из C++¶
Пример вызова C-функции из C++: при подключении заголовочного файла C нужно добавлять extern "C"
//add.h
#ifndef ADD_H
#define ADD_H
int add(int x,int y);
#endif
//add.c
#include "add.h"
int add(int x,int y) {
return x+y;
}
//add.cpp
#include <iostream>
#include "add.h"
using namespace std;
int main() {
add(2,3);
return 0;
}
Компиляция:
Линковка:
Без добавления extern "C" возникает ошибка:
> g++ add.cpp add.o -o main
add.o:在函数‘main’中:
add.cpp:(.text+0x0): `main'被多次定义
/tmp/ccH65yQF.o:add.cpp:(.text+0x0):第一次在此定义
/tmp/ccH65yQF.o:在函数‘main’中:
add.cpp:(.text+0xf):对‘add(int, int)’未定义的引用
add.o:在函数‘main’中:
add.cpp:(.text+0xf):对‘add(int, int)’未定义的引用
collect2: error: ld returned 1 exit status
После добавления extern "C":
add.cpp
#include <iostream>
using namespace std;
extern "C" {
#include "add.h"
}
int main() {
std::cout << add(2, 3) << std::endl;
return 0;
}
При компиляции обязательно обратите внимание: сначала сгенерируйте промежуточный файл add.o с помощью gcc.
Затем компиляция:
Если вы используете bazel, запустите: bazel run basic_content/extern/extern_c++:main
А чтобы код на C был универсальным — то есть вызывался как из C, так и из C++ — заголовочный файл обычно оформляют так:
То есть при вызове этого интерфейса из C++ вызов выполняется как вызов C-интерфейса. Такой способ избавляет программиста C++ от необходимости писать дополнительный extern C; похожим образом устроены и заголовочные файлы стандартной библиотеки — иначе почему вы можете напрямую пользоваться C-функциями из stdio.h без extern C?
Исходный код приведённого примера:
2.Вызов C++-функций из C¶
extern "C" в C — синтаксическая ошибка; его нужно помещать в заголовочный файл C++.
// add.h
#ifndef ADD_H
#define ADD_H
extern "C" {
int add(int x,int y);
}
#endif
// add.cpp
#include "add.h"
int add(int x,int y) {
return x+y;
}
// add.c
extern int add(int x,int y);
int main() {
add(2,3);
return 0;
}
Компиляция:
Линковка:
Исходный код приведённого примера:
Подводя итог, сформулируем правила использования: в заголовочных файлах языка C внешние функции можно объявлять только как extern; язык C не поддерживает объявление extern "C", и если в .c-файле встретится extern "C", возникнет синтаксическая ошибка компиляции. Поэтому extern "C" целиком помещают в файлы, связанные с cpp-программой, или её заголовочные файлы.
Обобщим в виде следующих схем:
(1)Вызов C-функции из C++:
(2)Вызов C++-функции из C
Впрочем, в отличие от вызова C-интерфейса из C++, C++ действительно может вызывать скомпилированные C-функции, тогда как здесь, при вызове C++ из C, код C++ просто компилируется как код C и затем вызывается. Иными словами, C не может напрямую вызывать библиотечные функции C++.
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- C++ битовые поля | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ константы const и его модификация | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ инициализация и присваивание | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事