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

extern "C" 詳解:C++ 調用 C 代碼的編譯鏈接機制與實戰模板

     編輯:關於C語言

核心問題:名字修飾

  • C 編譯器:void foo(int, int) → 符號 _foo(或 foo)。
  • C++ 編譯器:為支持重載,生成 _foo_int_int 等修飾名(mangled name),包含參數類型信息。
  • 直接混編:C++ 尋找 _foo_int_int,C 庫提供 _foo → 鏈接失敗 undefined reference。

extern "C" 解決方案


// 告訴 C++ 編譯器:大括號內按 C 規則編譯/鏈接(不修飾名字)
extern "C" {
    void foo(int x, int y);  // 符號為 _foo
    int  bar(double d);
}
  • 作用於聲明,指導 C++ 編譯器生成 C 風格符號引用。
  • 定義端(.c 文件)無需 extern "C",正常編譯即產生 C 符號。

標準跨語言頭文件模板


// foo.h —— 同時被 .c 和 .cpp 包含
#ifndef FOO_H
#define FOO_H

#ifdef __cplusplus
extern "C" {
#endif

// 這裡放純 C 接口:函數聲明、結構體定義(無方法)、宏
void foo(int x, int y);
int  compute(double *data, size_t n);

#ifdef __cplusplus
}
#endif

#endif // FOO_H

完整編譯鏈接演示


// foo.c (C 實現)
#include "foo.h"
#include 

void foo(int x, int y) { printf("sum=%d\n", x+y); }
int compute(double *d, size_t n) { /* ... */ return 0; }

// test.cpp (C++ 調用)
#include "foo.h"
#include 

int main() {
    foo(1, 2);  // 直接調用
    return 0;
}

// 編譯命令
gcc -c foo.c -o foo.o
g++ -c test.cpp -o test.o
g++ test.o foo.o -o test  // 鏈接成功
./test  // 輸出 sum=3

進階場景

C++ 類導出 C 接口(工廠模式)


// foo.h
#ifdef __cplusplus
extern "C" {
#endif

typedef struct Opaque *Handle;  // 不透明指針
Handle create_object();
void   destroy_object(Handle h);
int    do_work(Handle h, int param);

#ifdef __cplusplus
}
#endif

// foo.cpp
#include "foo.h"
#include "MyClass.hpp"

extern "C" Handle create_object() {
    return reinterpret_cast(new MyClass());
}
extern "C" void destroy_object(Handle h) {
    delete reinterpret_cast(h);
}
extern "C" int do_work(Handle h, int p) {
    return reinterpret_cast(h)->work(p);
}

常見誤區

  1. 以為定義端也要加:.c 文件不需也不應加 extern "C"。
  2. 用於 C++ 類成員函數:成員函數有 this,無法直接用 extern "C",需包裝為自由函數。
  3. 忽略頭文件保護:#ifndef/__cplusplus 結構確保 .c/.cpp 都能安全包含。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved