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

C 與 C++ 互相呼叫的實作指南:從 DLL 導出到名稱修飾完整解析

     編輯:更多程式設計知識

在跨語言專案開發中,C 與 C++ 的互操作是常見且關鍵的課題。由於 C++ 引入了名稱修飾機制以支援函數多載,直接呼叫 C 函數或被 C 程式碼呼叫時,若不加適當處理,連結器將找不到正確的符號。本文系統整理兩大核心場景的解決方案,並提供可直接套用的標準模式。

一、從 C 語言 DLL 導出函數供 C/C++ 共同使用

當以 C 語言編寫 DLL 並需提供給 C++ 模組呼叫時,關鍵在於防止 C++ 編譯器對函數名進行修飾。標準做法是利用 __cplusplus 預處理器宏,在標頭檔中以 extern "C" 包裹導出宣告:

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

__declspec(dllimport) void MyCFunc();
__declspec(dllimport) void AnotherCFunc();

#ifdef __cplusplus
}
#endif

此模式確保:

  • C 編譯器忽略 extern "C",正常編譯;
  • C++ 編譯器以 C 連結規格處理函數宣告,不進行名稱修飾;
  • 同一標頭檔可同時被 C 與 C++ 專案 #include,零修改復用。

若現有 C 標頭檔未採用上述技巧,而在 C++ 原始檔中需引用它,可在 #include 時以區塊包裹:

extern "C" {
#include "MyCHeader.h"
}

這樣即可強制編譯器將標頭檔內所有函數視為 C 連結,避免連結階段「找不到符號」錯誤。

二、從 C++ DLL 導出函數供 C 語言專案呼叫

反向情況下,C++ DLL 欲對 C 專案公開介面,同樣必須指定 C 連結。在 DLL 專案的函數定義前加上 extern "C":

extern "C" __declspec(dllexport) int MyFunc(long parm1);

這樣產生的符號名不經修飾,C 專案即可正常連結。但 C 程式碼無法直接呼叫 C++ 類別成員函數或使用 C++ 物件。常見解法是編寫 Wrapper 函數:以 C 連結導出的自由函數內部持有 C++ 物件指標,轉呼叫成員函數:

// Wrapper 函數:C 連結導出
extern "C" void call_Lib_CPPFunction(Lib* p, DataAttribute* dataAttribute) {
    p->daFun(dataAttribute);  // 實際呼叫 C++ 成員函數
}

// C++ 類別實現
void Lib::daFun(DataAttribute* dataAttribute) {
    std::map<std::string, MMSINFO>::iterator it;
    // ... 具體業務邏輯
}

此模式將 C++ 封裝性保留於 DLL 內部,對外僅暴露純 C 介面,實現語言隔離與二進位相容。

核心原則總結

  1. 統一連結規格:跨語言介面一律採用 extern "C"。
  2. 標頭檔防禦性設計:善用 __cplusplus 宏,使單一標頭檔同時服務 C/C++。
  3. 物件生命週期由 DLL 管理:C 端僅持有不透明指標,避免跨語言記憶體佈局差異導致未定義行為。

遵循上述模式,即可構建穩健、可維護的 C/C++ 混合專案架構。

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