English: extern "C" tells the C++ compiler to use C linkage for a declaration or definition, which mainly disables C++ name mangling.
中文: extern "C" 告诉 C++ 编译器:这个声明或定义要使用 C 链接方式 ,最主要的效果就是关闭 C++ 的名字重整。
English: It does not mean "compile this file as C". It only changes symbol linkage.
中文: 它并不表示"把这个文件按 C 来编译",它只是改变符号链接方式。
实验 1:.c 和 .cpp 都用 g++ 编译
.c & .cpp both compile with g++
main.cpp
cpp
#include <iostream>
#include "test.h"
// extern "C" void show();
void test01()
{
show();
}
int main()
{
test01();
return EXIT_SUCCESS;
}
test.h
cpp
#include <stdio.h>
void show();
test.c
cpp
#include "test.h"
void show()
{
printf("hello world.\n");
}
both get C++ linkage
g++ main.cpp test.c -o main
bash
shaoyoulu@shaoyoulu:~/Code/extern$ g++ main.cpp test.c -o main
shaoyoulu@shaoyoulu:~/Code/extern$ ./main
hello world.
English: When you run g++ main.cpp test.c -o main, both files are compiled as C++ translation units. The .c suffix does not force C mode when the compiler is g++.
中文: 当你执行 g++ main.cpp test.c -o main 时,这两个文件都会被当成 C++ 翻译单元 编译。.c 后缀并不会强制让 g++ 进入 C 模式。
English: That is why the program works even without extern "C": both declaration and definition are C++ linkage, so they match.
中文: 这就是为什么即使没有 extern "C",程序也能运行:因为声明和定义都被当成 C++ 链接方式,所以符号是匹配的。
English: This experiment proves only one thing: g++ compiles .c files as C++ when you ask g++ to compile them.
中文: 这个实验只证明了一件事:当你让 g++ 去编译时,它会把 .c 文件也按 C++ 处理。
实验 2:main.cpp 用 g++,test.c 用 gcc,但没有 extern "C"
.cpp compile with g++, .c compile with gcc
without extern "C" void show();
bash
shaoyoulu@shaoyoulu:~/Code/extern$ g++ -c main.cpp -o main.o
shaoyoulu@shaoyoulu:~/Code/extern$ gcc -c test.c -o test.o
shaoyoulu@shaoyoulu:~/Code/extern$ g++ main.o test.o -o main
/usr/bin/ld: main.o: in function `test01()':
main.cpp:(.text+0x9): undefined reference to `show()'
collect2: error: ld returned 1 exit status
shaoyoulu@shaoyoulu:~/Code/extern$
undefined reference to `show()'
English: This is the real mixed C/C++ test. gcc compiles test.c as C, so show has C linkage. g++ compiles main.cpp as C++, so show() in the declaration has C++ linkage by default.
中文: 这才是真正的 C/C++ 混合测试。gcc 把 test.c 按 C 编译,所以 show 是 C 链接;g++ 把 main.cpp 按 C++ 编译,所以 show() 的声明默认是 C++ 链接。
English: The linker then sees two different symbols: one unmangled C symbol and one mangled C++ symbol. So it reports undefined reference to show().
中文: 于是链接器看到的是两个不同的符号:一个是未重整的 C 符号,一个是 C++ 重整后的符号,所以报 undefined reference to show()。
实验 3:在 main.cpp 中加上 extern "C" void show();
with extern "C" void show();
main.cpp
bash
#include <iostream>
//#include "test.h"
extern "C" void show();
void test01()
{
show();
}
int main()
{
test01();
return EXIT_SUCCESS;
}
bash
shaoyoulu@shaoyoulu:~/Code/extern$ g++ -c main.cpp -o main.o
shaoyoulu@shaoyoulu:~/Code/extern$ gcc -c test.c -o test.o
shaoyoulu@shaoyoulu:~/Code/extern$ g++ main.o test.o -o main
shaoyoulu@shaoyoulu:~/Code/part1/extern$ ./main
hello world.
shaoyoulu@shaoyoulu:~/Code/extern$
English: Now the C++ compiler is told to treat show as a C-linked symbol. It no longer mangles the name, so the declaration matches the C definition compiled by gcc.
中文: 这时 C++ 编译器被告知:show 是 C 链接符号,不要重整名字。于是这个声明就能和 gcc 编译出来的 C 定义匹配上。
English: That is why the program links and runs correctly.
中文: 这就是为什么程序能正确链接并运行。
important concepts to emphasize
1 extern "C" 的本质
English: extern "C" is a linkage specification, not a storage class and not a compiler switch.
中文: extern "C" 是一种链接说明,不是存储类别,也不是编译器开关。
English: Its main purpose is to make C+±compiled code produce C-compatible symbols.
中文: 它的主要目的,是让 C++ 编译出来的代码生成 C 兼容的符号名。
2 C++ 为什么需要它
English: C++ supports function overloading, namespaces, and more advanced type information, so it encodes extra information into symbol names. This is name mangling.
中文: C++ 支持函数重载、命名空间以及更复杂的类型信息,所以它会把额外信息编码进符号名,这就是名字重整。
English: C does not need that, so C symbols are simple and unmangled.
中文: C 不需要这些机制,所以 C 的符号名通常是简单直接的、不会重整。
3 extern "C" 不能做什么
English: extern "C" does not magically make C code legal in a C++ file. It only changes linkage.
中文: extern "C" 不会让 C 代码在 C++ 文件里"自动合法",它只改变链接方式。
English: It also does not make two different function signatures compatible. The parameter types and return type still must match.
中文: 它也不会让两个不同函数签名变成兼容。参数类型和返回值类型仍然必须匹配。
extern "C"标准写法
头文件写法 / Header pattern
test.h
cpp
#ifdef __cplusplus
extern "C"{
#endif
#include <stdio.h>
void show();
#ifdef __cplusplus
}
#endif
English: This is the standard mixed C/C++ header pattern.
中文: 这是标准的 C/C++ 混合头文件写法。
English: If the header is included by C++ code, show gets C linkage. If it is included by C code, the extern "C" part is ignored because __cplusplus is not defined.
中文: 如果这个头文件被 C++ 代码包含,show 就会获得 C 链接;如果被 C 代码包含,因为 __cplusplus 没定义,extern "C" 那部分就会被跳过。
main.cpp
cpp
#include <iostream>
#include "test.h"
void test01()
{
show();
}
int main()
{
test01();
return EXIT_SUCCESS;
}
test.c
cpp
#include "test.h"
void show()
{
printf("hello world.\n");
}
bash
shaoyoulu@shaoyoulu:~/Code/extern$ g++ -c main.cpp -o main.o
shaoyoulu@shaoyoulu:~/Code/extern$ gcc -c test.c -o test.o
shaoyoulu@shaoyoulu:~/Code/extern$ g++ main.o test.o -o main
shaoyoulu@shaoyoulu:~/Code/part1/extern$ ./main
hello world.
shaoyoulu@shaoyoulu:~/Code/extern$
extern "C" 出现在声明端还是定义端
English: In mixed-language projects, the most common practice is to put extern "C" in the header declaration, so both C and C++ translation units stay consistent.
中文: 在混合语言工程中,最常见的做法是把 extern "C" 放在头文件声明处,这样 C 和 C++ 的翻译单元都能保持一致。
English: If both declaration and definition are compiled as C++, then both sides must agree on C linkage if you want a C symbol.
中文: 如果声明和定义都按 C++ 编译,那么两边都必须约定使用 C 链接,否则不会得到 C 符号。
extern "C" 和重载
English: Functions declared with extern "C" cannot be overloaded, because C linkage does not carry type information for overload resolution.
中文: 被声明为 extern "C" 的函数不能重载,因为 C 链接不携带用于重载解析的类型信息。
English: This is another important reason why extern "C" is only for interface boundaries.
中文: 这也是为什么 extern "C" 主要用于接口边界,而不是随便在内部代码里乱用。
纯 C++,不需要 extern "C"
English: Show that compiling everything with g++ makes the program work because everything is C++.
中文: 先展示"全部用 g++ 编译"时程序能工作,因为整个程序都被当成 C++。
真正的 C + C++ 混编,必须用 extern "C"
English: Then show g++ main.cpp + gcc test.c, and let it fail without extern "C".
中文: 然后展示 g++ main.cpp + gcc test.c,在没有 extern "C" 时失败。
加上 extern "C" 后成功
English: Finally, add the extern "C" guard in the header or declaration, and show the link succeeds.
中文: 最后加上头文件里的 extern "C" 保护,展示链接成功。
Misconceptions
English: Misconception 1: .c files are always compiled as C.
中文: 误区 1:.c 文件总是按 C 编译。
English: Correction: the compiler determines the language mode. g++ will compile .c files as C++.
中文: 更正:语言模式由编译器决定。g++ 会把 .c 文件按 C++ 编译。
English: Misconception 2: extern "C" changes runtime calling behavior.
中文: 误区 2:extern "C" 会改变运行时调用行为。
English: Correction: it mainly changes symbol linkage and mangling, not the high-level function logic.
中文: 更正:它主要改变的是符号链接和名字重整,不改变函数逻辑本身。
English: Misconception 3: Once extern "C" is added, any C and C++ code can freely mix.
中文: 误区 3:加了 extern "C" 后,C 和 C++ 就能随便混用。
English: Correction: types, headers, memory management, and API conventions still must be compatible.
中文: 更正:类型、头文件、内存管理、API 约定仍然必须兼容。