我們開發了一些簡單的項目C
(C99)。但是,我們在C++
中有一個作爲源代碼的庫(數學庫)。我們需要這個庫,所以我想問一下,整合這個源代碼最優雅的方式是什麼?從C中優雅地調用C++
尺寸爲C
和C++
之間的比率爲20:1
因此不能選擇C++
。我們應該使用靜態庫嗎? DLL? (全部在Windows上)。
我們開發了一些簡單的項目C
(C99)。但是,我們在C++
中有一個作爲源代碼的庫(數學庫)。我們需要這個庫,所以我想問一下,整合這個源代碼最優雅的方式是什麼?從C中優雅地調用C++
尺寸爲C
和C++
之間的比率爲20:1
因此不能選擇C++
。我們應該使用靜態庫嗎? DLL? (全部在Windows上)。
編輯:基於在評論的討論,我要指出的是分離的東西到C兼容struct duck
和派生class Duck
可能是不必要的。您可能可以安全地將執行鏟入struct duck
並消除class Duck
,從而避免real(…)
。但是我不太瞭解C++(尤其是它與C宇宙交互的方式),以便爲此提供明確的答案。
沒有理由你不能簡單地鏈接所有的C和C++代碼一起到一個單一的二進制文件。
與C++代碼的接口需要將C++ API封裝到C API中。你可以通過在編譯C++代碼時在extern "C" { ... }
內聲明一堆函數,並且在編譯C客戶端代碼時不用extern聲明來實現。例如:
#ifdef __cplusplus
extern "C" {
#endif
typedef struct duck duck;
duck* new_duck(int feet);
void delete_duck(duck* d);
void duck_quack(duck* d, float volume);
#ifdef __cplusplus
}
#endif
你可以在你的C++源定義鴨結構,甚至從它繼承了真正的Duck
類:
struct duck { };
class Duck : public duck {
public:
Duck(int feet);
~Duck();
void quack(float volume);
};
inline Duck* real(duck* d) { return static_cast<Duck*>(d); }
duck* new_duck(int feet) { return new Duck(feet); }
void delete_duck(duck* d) { delete real(d); }
void duck_quack(duck* d, float volume) { real(d)->quack(volume); }
很好的答案,謝謝! – Cartesius00
國際海事組織空白指針會更適合在這裏 – Ulterior
@Ulterior:不IMO。如果你把鴨子和青蛙當成空針,你可能會不小心讓青蛙嘎嘎作響,這會撕裂宇宙的結構。 –
的唯一原因想從鴨結構繼承會在C API中公開一些屬性,無論如何這通常被認爲是不好的風格。沒有繼承,你的C頭應該是這樣的:
struct Duck;
struct Duck* new_Duck(int feet);
void delete_Duck(struct Duck* d);
void Duck_quack(struct Duck* d, float volume);
,這將是相應的實施,而無需類型轉換:
extern "C" {
#include "Duck.h"
}
class Duck {
public:
Duck(int feet) : {}
~Duck() {}
void quack(float volume) {}
};
struct Duck* new_Duck(int feet) { return new Duck(feet); }
void delete_Duck(struct Duck* d) { delete d; }
void Duck_quack(struct Duck* d, float volume) { d->quack(volume); }
以同樣的方式,一個C API可爲C++接口(純虛擬類)及其實現創建。在這種情況下,只有構造函數需要基於具體實現(例如new_RubberDuck(2))。析構函數和所有其他函數將自動在正確的實現上運行,與C++中的一樣。
函數實現也應該被標記爲extern「C」。否則,你會得到鏈接錯誤,因爲「new_Duck :: i」或者你的平臺上的任何名字使得C++函數與頭文件的「new_Duck」不匹配。 – uliwitness
C++數學庫很可能在實用程序類(僅限靜態成員)中實現。在這種情況下,一個更簡單的方法可以採取:
class FPMath {
public:
static double add(double, double);
static double sub(double, double);
static double mul(double, double);
static double div(double, double);
};
針對C接口的頭然後將:
double FPMath_add(double, double);
double FPMath_sub(double, double);
double FPMath_mul(double, double);
double FPMath_div(double, double);
和相應的實現可能是:
double FPMath_add(double a, double b) { return FPMath::add(a, b); }
double FPMath_sub(double a, double b) { return FPMath::sub(a, b); }
double FPMath_mul(double a, double b) { return FPMath::mul(a, b); }
double FPMath_div(double a, double b) { return FPMath::div(a, b); }
但也許這是明顯的....
There is一種創建「黑客」的方法,允許您直接調用某些對象的成員函數。
您需要做的第一件事是創建一個extern "C"
工廠函數,該函數返回一個指針(如void*
)到對象。
您需要的第二件事是成員函數的損壞名稱。
然後,您可以使用mangled名稱並將工廠函數返回的指針作爲第一個參數傳遞給該函數。
注意事項:
當然這不是我推薦的,事實上恰恰相反。我強烈建議不要執行此答案中概述的內容。它不受支持,可能未定義行爲,並可能以怪異和不可預知的方式打破。
C++庫是否提供了一個合適的C接口(自由函數而不是成員函數,沒有例外,extern「C」等)? –
混合C和C++的常見問題解答:http://www.parashift.com/c++-faq/mixing-c-and-cpp.html – Maciej
[如何從C調用C++函數](http:// stackoverflow.com/questions/2744181/how-to-call-c-function-from-c) –