2008-10-13 59 views
84

我有一個C++庫,它提供了用於管理數據的各種類。我有圖書館的源代碼。在C代碼中使用C++庫

我想擴展C++ API以支持C函數調用,以便該庫可以與C代碼和C++代碼同時使用。

我使用GNU工具鏈(gcc,glibc等),因此語言和體系結構支持不是問題。

是否有任何理由這在技術上不可能?

是否有任何gotcha的我需要注意什麼?

是否有關於此的資源,示例代碼和/或文檔?


,我已經發現了一些其他的事情:

  1. 使用以下來包裝你的C++需要由C代碼中使用標頭。

#ifdef __cplusplus 
extern "C" { 
#endif 
// 
// Code goes here ... 
// 
#ifdef __cplusplus 
} // extern "C" 
#endif 
  • 保持 「真正的」 C++在單獨的頭文件不是由C.包括接口想到PIMPL principle這裏。使用#ifndef __cplusplus #error東西有助於在這裏檢測到任何瘋狂。
  • 小心C代碼作爲C代碼中的名稱
  • 在C和C++編譯器之間枚舉大小不同。如果您使用GNU工具鏈,可能不是問題,但仍然要小心。
  • 對於結構遵循以下形式,以便C不會感到困惑。

    typedef struct X { ... } X 
    
  • 然後使用指針繞過C++對象,他們只是在C聲明爲結構體X,其中X是C++的對象。

  • 所有這些都是由一位在C++中的嚮導的朋友提供的。

    +3

    有點晚了,但是我寫了一個關於C++的C封裝的小指令:http://www.teddy.ch/c++_library_in_c/ – Teddy 2015-07-20 20:09:26

    回答

    62

    是的,這當然是可以的。您將需要與extern "C" C++編寫聲明功能的接口層:

    extern "C" int foo(char *bar) 
    { 
        return realFoo(std::string(bar)); 
    } 
    

    然後,你會打電話給foo()從你的C模塊,這將傳遞到在C++實現的realFoo()函數的調用。

    如果您需要使用數據成員和方法公開完整的C++類,那麼您可能需要做的工作比這個簡單的函數示例更多。

    +0

    只應該在聲明中放置「extern」C「不在定義中)?因爲您提到了「聲明函數的圖層」,但您的示例代碼也是一個定義。 換句話說,我們應該把它放在頭文件還是源文件?(或兩者兼而有之?) – KyrSt 2017-10-15 17:40:18

    +0

    @KyrSt:如果你有一個帶有函數聲明的頭文件,那麼你必須至少把`extern「C」`放在那裏。您的編譯器會告訴您是否還必須將其放在定義上。 – 2017-10-16 03:15:03

    3

    您可以混合使用C/C++代碼。如果您的main()在C++函數,那麼你只需要確保你的C函數聲明

    extern "C" 
    

    如果你的主要是C,那麼你可能除了靜態變量確定。任何具有靜態變量的構造函數應該在main()開始之前調用。如果C是你的主體,這不會發生。我有很多靜態變量,最好的辦法是用單例替換靜態變量。

    11

    主要問題:異常無法在C中捕獲。如果在C++代碼中可能出現異常,請仔細寫出C代碼或C++包裝。相反,C代碼中的機制(即longjump)等異常(如各種腳本語言中所示)不需要爲堆棧上的C++對象調用析構函數。

    18

    C++ FAQ Lite:"How to mix C and C++ code"

    一些陷阱中的答案被描述這些問題:

    • [32.8]如何通過C++類到/的目的從C函數?
    • [32.9]我的C函數可以直接訪問C++類的對象中的數據嗎?