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

extern "C" 深度解析:C/C++ 混合編程的橋樑

     編輯:關於C語言

雙重含義

  1. 外部連結 (extern):聲明符號在其他編譯單元定義,連結器需跨文件解析。
  2. C 語言連結規範 ("C"):指示編譯器對該聲明/定義採用 **C 風格名稱修飾 (Name Mangling)**,而非 C++ 風格。

為什麼需要 "C" 連結?

C++ 支援函數重載,編譯器將函數簽名 (參數類型、個數、命名空間、類別) 編碼進符號名稱 (Mangled Name),如 void foo(int, float) → _Z3fooif (GCC) 或 ?foo@@YAXHM@Z (MSVC)。
C 無重載,符號名通常僅加前綴底線 _foo。
若 C++ 直接調用 C 函數,連結器會尋找 C++ 風格符號而失敗。

核心用法四大場景

1. C++ 調用 C 庫 (最常見)

[cpp]
// cExample.h (C 標頭檔)
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x, int y); // 僅 extern,不可加 extern "C"
#endif

// cExample.c
#include "cExample.h"
int add(int x, int y) { return x + y; }

// cppFile.cpp (C++ 使用)
extern "C" {
    #include "cExample.h" // 整個標頭檔包在 extern "C" 區塊
}
int main() { add(2, 3); return 0; }

編譯鏈:gcc -c cExample.c -o cExample.o → g++ cppFile.cpp cExample.o -o cppFile。

2. C 調用 C++ 庫

[cpp]
// cppExample.h (C++ 標頭檔,對外暴露 C 介面)
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
#ifdef __cplusplus
extern "C" {
#endif
    int add(int x, int y); // C++ 實現,但用 C 連結
#ifdef __cplusplus
}
#endif
#endif

// cppExample.cpp
#include "cppExample.h"
int add(int x, int y) { return x + y; }

// cFile.c (C 使用)
// 錯誤:#include "cppExample.h" (C 編譯器不識別 extern "C")
// 正確:僅聲明
extern int add(int x, int y);
int main() { add(2, 3); return 0; }

3. C++ 專案中混編 .c 文件

在 C++ 文件包含 C 標頭檔時,務必加 extern "C" 區塊;若直接在 C++ 中定義需給 C 用的函數,定義處也需加:

[cpp]
// 定義在 .cpp 中,供 C 調用
extern "C" int my_c_func(int x) { return x * 2; }

4. 動態庫 導出 C 介面

Windows .dll / Linux .so 導出函數給不同語言調用,必須用 extern "C" 避免名稱修飾,否則 GetProcAddress/dlsym 需知具體修飾名極不便。

進階技巧:__cplusplus 守護宏

使同一標頭檔同時適配 C 與 C++:

[c]
// mylib.h
#ifndef MYLIB_H
#define MYLIB_H

#ifdef __cplusplus
extern "C" {
#endif

int mylib_add(int a, int b);
void mylib_init(void);

#ifdef __cplusplus
}
#endif

#endif

常見坑點彙總

現象原因修正
C++ 編譯 .c 文件報錯g++ file.c 以 C++ 模式編譯 C 代碼gcc -c file.c 產 .o 再 g++ main.cpp file.o
連結錯誤: undefined reference聲明有 extern "C" 但定義無,或反之聲明與定義**連結規範必須一致**
C 文件包含含 extern "C" 的頭文件報錯C 編譯器不識別 extern "C"頭文件用 #ifdef __cplusplus 守護
類成員函數加 extern "C"非靜態成員函數有 this 指標,無法用 C 連結僅靜態成員函數或自由函數可用

總結

extern "C" 是 **C/C++ 混合編程、動態庫導出、跨語言調用 (Python ctypes, Java JNI, C# P/Invoke)** 的基石。核心口訣:聲明與定義處連結規範對齊,頭文件用 __cplusplus 守護,編譯分離 .c/.cpp 產 .o 再鏈接。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved