C++ 支援**函數多載**,編譯器對函數進行 **Name Mangling (修飾)**,將函數名、參數型別、命名空間編碼進符號名 (如 `_Z3fooi`)。C 語言**無修飾**,符號即函數名 (如 `foo`)。若 C++ 直接呼叫 C 函數,連結器找不到修飾後的符號 → **連結錯誤**。
#ifndef MYLIB_H
#define MYLIB_H
#ifdef __cplusplus
extern "C" {
#endif
/* C 風格介面:函數宣告、結構體定義、宏常數 */
void mylib_init(void);
int mylib_process(int input);
typedef struct { int x; int y; } Point;
#ifdef __cplusplus
}
#endif
#endif /* MYLIB_H */
/* C 庫頭文件 c_lib.h */
#ifndef C_LIB_H
#define C_LIB_H
#ifdef __cplusplus
extern "C" {
#endif
int c_add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
/* C++ 使用端 */
extern "C" {
#include "c_lib.h"
}
int main() { return c_add(2, 3); }
/* C++ 庫實作 cpp_lib.cpp */
extern "C" int cpp_add(int a, int b) { return a + b; } // 導出 C 符號
/* C++ 庫頭文件 cpp_lib.h */
#ifdef __cplusplus
extern "C" {
#endif
int cpp_add(int a, int b); // C++ 端見 C 連結
#ifdef __cplusplus
}
#endif
/* C 使用端 c_main.c */
extern int cpp_add(int a, int b); // 僅宣告 extern
int main() { return cpp_add(2, 3); }
**關鍵**:C 端**不能**包含含 `extern "C"` 的頭文件,只能單獨 `extern` 宣告。
/* Windows DLL */
#ifdef BUILDING_DLL
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
DLL_API int dll_add(int a, int b);
#ifdef __cplusplus
}
#endif
/* Linux .so */
#define DLL_API __attribute__((visibility("default")))
/* 其餘相同 */
動態庫導出符號**必須**為 C 連結,否則 Python `ctypes`、Java JNI、C# `DllImport`、Go `cgo` 等均無法正確解析符號。
/* C 庫回呼型別 */
typedef void (*Callback)(int event, void *user_data);
/* C++ 類靜態成員函數可直接轉型 */
class Handler {
public:
static void on_event(int event, void *user_data) {
auto *self = static_cast(user_data);
self->process(event);
}
void process(int event) { /* ... */ }
};
/* 註冊 */
register_callback(Handler::on_event, this);
| 原始碼 | C 符號 (GCC) | C++ 符號 (GCC, Itanium ABI) |
|---|---|---|
| `int foo();` | `foo` | `_Z3foov` |
| `int foo(int);` | `foo` | `_Z3fooi` |
| `int foo(int, double);` | `foo` | `_Z3fooid` |
| `namespace N { int foo(); }` | N/A | `_ZN1N3fooEv` |
| 錯誤 | 原因 | 修正 |
|---|---|---|
| C 檔案編譯報 `expected identifier` 在 `extern "C"` | C 編譯器不支援 `extern "C"` | 用 `#ifdef __cplusplus` 包裹 |
| 連結錯誤 `undefined reference to foo` | C++ 端未用 `extern "C"` 包含 C 頭文件 | 補上 `extern "C" { #include "c.h" }` |
| C++ 類成員函數作為 C 回呼崩潰 | 非靜態成員函數有隱含 `this`,呼叫慣例不符 | 用 `static` 成員函數或自由函數 + `user_data` 傳 `this` |
| 動態庫 `dlopen` 找不到符號 | 導出函數未加 `extern "C"` | 導出介面全部包裹 `extern "C"` |
`extern "C"` 是 **C/C++ 混合編程、動態庫導出、跨語言 FFI (Foreign Function Interface) 的基石**。掌握 **Name Mangling 原理、頭文件護衛模式、四大應用場景、符號驗證方法**,能讓你在嵌入式固件、插件系統、語言綁定、高效能庫開發等領域自信處理跨語言邊界。