c++是C的超集,不可避免的要兼容C的特性,C++在C基礎山的拓展部分叫做C with class,同時C++有自己特有的屬性比如模板template. C並不完全是C++的子集.
那么如何在C/C++中設計接口,實現相互調用呢?我們經常在C++代碼中看見extern C的語句,那么其目的是什么呢?
C/C++程序中的函數在鏈接階段對應的符號標識稱為修飾名,是由編譯器按某種規則生成的一個字符串,在compiling階段創建,linking階段使用。它就象函數的身份證號,必須唯一,后續才能被正確索引。
C中不容許函數重載,也就是相同的函數名只能聲明定義一個函數,而C++中函數重載是被容許的。int func(int a), int func(double a),C++中引入了name mangling,在編譯的時候,對於相同名字的func 會根據其參數和函數名生成一個unique的函數名。然后連接器linker就會連接到重載的函數中,
- 如何在C++中exposed interface as C style API,也就是如何暴露C API給外部client使用,假設C client需要調用C++的函數,那么我們通過引入extern C告訴C++編譯器按C 規則編譯函數代碼,也就是不name mangling. 否則符號表會找不到對應的符號。因為C中函數修飾名就是函數名,如果用C++編譯,會有name mangling,那么linker 會找不到對應的實現.無法連接.
- 如何在C++調用C代碼,還是引入extern C,告訴C++編譯器函數用C的方式去鏈接。 以上的區別是一個是complie function as C api 和 linker function as C api.
在實現中我們可以看見:C++調用C函數 注意ifdef -cplusplus的用法。如果是C++那么就用C形式linker,此時外部llibrary就是C庫..
//C_library.h
#ifdef __cplusplus extern "C" { #endif // // ... prototypes for C_library go here ... // #ifdef __cplusplus } #endif
// // C_library.c // #include "C_library.h" // // ... implementations for C_library go here ... //
// // C++_code.cpp // #include "C_library.h" #include "C++_code.h" // // ... C++_code implementation here may call C functions in C_library.c ... //
C/C++混編已經介紹完,那么為什么平常我們的第三方庫往往都是C API形式的呢?因為C++形式的ABI 二進制接口沒有統一規范. 如果采用第三方庫1.0之后,對方進行了升級到2.0,很有可能會造成庫的二進制文件內存布局的變化,導致不兼容。不能只更新第三方庫。還需要編譯整個項目。生產環境很不推薦在dll里暴露C++接口,尤其是模板接口。因為除非所有的binary都在你的控制之下,否則他們一旦使用的編譯器不同(版本不同也算),就極有可能內存miss match垮掉。