首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

extern "C" 深度解析:C++ 調用 C 代碼的編譯鏈接機制

     編輯:關於C

C++ 專案調用 C 庫時,`extern "C"` 是必須跨越的門檻。本文從符號修飾原理、編譯鏈接差異、頭文件寫法、實戰構建流程四維度徹底講透。

核心問題:名字修飾 (Name Mangling)

C++ 支持函數重載,編譯器需在符號表編碼參數類型:

鏈接階段,C++ 目標文件尋找 `_foo_int_int`,C 庫提供 `_foo`,**符號不匹配 → `undefined reference`**。

extern "C" 解決方案

// 告訴 C++ 編譯器:用 C 規則生成符號 (不修飾)
extern "C" {
    void foo(int x, int y);  // 符號為 _foo
}

鏈接時能找到 C 庫導出的 `_foo`,完美對接。

標準頭文件雙語寫法 (foo.h)

#ifdef __cplusplus
extern "C" {
#endif

// 純 C 宣告,雙語通用
extern int foo(int x, int y);

#ifdef __cplusplus
}
#endif
  • C 編譯器忽略 `extern "C"` 塊,正常處理。
  • C++ 編譯器識別 `__cplusplus` 宏,啟用 C 鏈接規範。

完整構建演示

// foo.h (如上)
// foo.c
#include "foo.h"
int foo(int x, int y) { return x + y; }

// test.cpp
#include "foo.h"
#include 
int main() { printf("Hello %d\n", foo(1,2)); }

// 編譯鏈接
gcc -c foo.c -o foo.o      // C 編譯
g++ -c test.cpp -o test.o  // C++ 編譯
g++ test.o foo.o -o test   // C++ 鏈接器鏈接 .o
./test  // Hello 3

進階場景

  1. C++ 實現 C 接口:`extern "C" void c_api() { /* C++ 代碼 */ }` 供 C 調用。
  2. 類成員函數:`extern "C"` **不能**修飾非靜態成員函數 (隱含 `this`),只能用於 `static` 成員或自由函數。
  3. 模板/重載:`extern "C"` 函數不可重載 (符號無修飾),同名會衝突。
  4. 動態庫 dlopen:`dlsym(handle, "foo")` 尋找 C 風格符號,配合 `extern "C"` 導出。

常見誤區

  • 以為 `extern "C"` 改變調用約定 — **不變**,僅影響符號名;調用約定由 `__cdecl`/`__stdcall` 等控制。
  • 在 `.cpp` 文件內部包含 C 頭文件時忘記 `extern "C"` — 導致符號修飾不匹配。
  • 混淆 `extern` (作用域聲明) 與 `extern "C"` (鏈接規範) — 兩者可組合:`extern "C" int foo();` 同時聲明外部鏈接且 C 符號。

搞懂符號修飾與 `extern "C"`,C/C++ 混合編程不再踩坑!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
語言函數原型符號表名稱 (示例)
C`void foo(int, int);``_foo`
C++`void foo(int, int);``_foo_int_int` (編碼參數)
C++`void foo(int, float);``_foo_int_float`