C 與 C++ 接口函數(shù)相互調(diào)用的實(shí)現(xiàn)
一、C 或 C++ 編譯的四個(gè)步驟
(一) 預(yù)處理
在該步驟中,編譯器將源程序中以“#”開頭的語句進(jìn)行處理。其中,#include 的原理是將目標(biāo)文件內(nèi)容導(dǎo)入本文件。
(二) 編譯
在該步驟中,編譯器將第一步生成的各個(gè)文件分別轉(zhuǎn)換成匯編語言文件。在該過程中,所有函數(shù)的名稱都會(huì)被轉(zhuǎn)換成一個(gè)符號(hào)作為匯編文件中的唯一標(biāo)識(shí),對(duì) C 語言函數(shù)一般直接用函數(shù)名稱作為其唯一標(biāo)識(shí)的符號(hào),而對(duì)于 C++ 函數(shù)在多數(shù)情況下需要在函數(shù)名稱加上各種前綴或后綴才能作為其標(biāo)識(shí),比如函數(shù) void Print(int num),如果編譯器將其視為 C 語言編譯,則該函數(shù)在匯編文件中的符號(hào)為 Print,若視為 C++,則其符號(hào)可能為 Print_int(在 gcc 或 g++ 中函數(shù)名稱的改變還會(huì)考慮命名空間等因素),這也是 C++ 支持函數(shù)重載的原因。
(三) 匯編
在該步驟中,編譯器將第二步生成的各個(gè)文件分別轉(zhuǎn)換為二進(jìn)制文件,但還不是可執(zhí)行文件。
(四) 鏈接
在該步驟中,編譯器會(huì)為第三步生成的每一個(gè)文件“穿針引線”,比如 main() 函數(shù)中調(diào)用了 Print() 函數(shù),還不知道 Print() 函數(shù)在哪里,而在 Print() 函數(shù)主體所在的那個(gè)文件中,已經(jīng)標(biāo)明了 Print() 函數(shù)的地址,所以編譯器會(huì)在 main() 函數(shù)中調(diào)用 Print() 函數(shù)的地方標(biāo)注 Print() 函數(shù)的地址,為程序執(zhí)行過程中的地址跳轉(zhuǎn)提供目標(biāo)地址,而編譯器能做到這一步的前提,是 main() 函數(shù)中 Print() 函數(shù)的標(biāo)識(shí),和 Print() 函數(shù)主體所在的那個(gè)文件中 Print() 函數(shù)的標(biāo)識(shí)是一模一樣的,如果不一樣,就會(huì)觸發(fā)鏈接錯(cuò)誤。
二、C 與 C++ 接口相互調(diào)用的關(guān)鍵
從上文可以得知,要調(diào)用一個(gè)函數(shù)有一個(gè)重要條件就是調(diào)用處的符號(hào)和函數(shù)主體處的符號(hào)要一模一樣,而 C 和 C++ 在編譯過程中將函數(shù)名稱改編成標(biāo)識(shí)符號(hào)的方法是不一樣的,因此相互調(diào)用的關(guān)鍵在于統(tǒng)一接口函數(shù)的標(biāo)識(shí)符號(hào),而一般采取的方法是,用 C 函數(shù)改編的方法統(tǒng)一接口函數(shù)的改編方式。
三、extern "C"
extern "C" 的作用是告訴編譯器按 C 函數(shù)名稱改編的方法將修飾的函數(shù)改編成標(biāo)識(shí)符號(hào)。extern "C" 一般用在 C++ 文件中。
extern "C" void Print(int num); extern "C" { void Input(int* num); void Output(int num); };
以上是 extern "C" 的兩種寫法。如此一來,以上三個(gè)函數(shù)都會(huì)按 C 的方式被改編成符號(hào),在 gcc 或 g++ 編譯下就會(huì)被改變成 Print,Input,Output。
四、C 函數(shù)調(diào)用 C++ 接口
(一) 調(diào)用非成員函數(shù)
被調(diào)用函數(shù)的聲明和定義如下。
/** * called.h */ #ifndef CALLED_H #define CALLED_H extern "C" void PrintCpp(void); #endif
/** * called.cpp */ #include <iostream> #include "called.h" using namespace std; void PrintCpp(void) { cout << "I\'m cpp." << endl; }
最終調(diào)用如下。
/** * call.c */ #include "called.h" int main(int argc, char const* argv[]) { PrintCpp(); return 0; }
(二) 調(diào)用類成員函數(shù)(接口函數(shù)沒有類指針)
被調(diào)用函數(shù)聲明和定義如下。
/** * called.h */ #ifndef CALLED_H #define CALLED_H class Console { public: Console(); virtual void PrintDouble(double num); }; extern "C" void CppPrintDouble(double num); #endif
/** * called.cpp */ #include <iostream> #include "called.h" using namespace std; Console::Console() {} void Console::PrintDouble(double num) { cout << num << endl; } Console* console = new Console(); void CppPrintDouble(double num) { console->PrintDouble(num); }
最終調(diào)用如下。
/** * call.c */ #include "called.h" int main(int argc, char const* argv[]) { CppPrintDouble(3.14); return 0; }
五、C++ 函數(shù)調(diào)用 C 接口
被調(diào)用函數(shù)的聲明和定義如下。
/** * called.h */ #ifndef CALLED_H #define CALLED_H void PrintC(void); #endif
/** * called.c */ #include <stdio.h> #ifdef __cplusplus extern "C" { #endif #include "called.h" #ifdef __cplusplus }; #endif void PrintC(void) { printf("I\'m C.\n"); }
最終調(diào)用如下。
/** * call.cpp */ #ifdef __cplusplus extern "C" { #endif #include "called.h" #ifdef __cplusplus }; #endif int main(int argc, char const* argv[]) { PrintC(); return 0; }
在 called.c 文件中,#ifdef __cplusplus /*...*/ #endif 和 extern "C" 的作用是防止 g++ 編譯器對(duì)“.c”文件用 C++ 的方式編譯,如果用 gcc 進(jìn)行編譯,則直接寫 #include "called.h" 就行。
到此這篇關(guān)于C 與 C++ 接口函數(shù)相互調(diào)用的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C 與 C++ 接口函數(shù)調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11 shared_ptr 與 make_shared源碼剖析詳解
這篇文章主要介紹了C++11 shared_ptr 與 make_shared的源碼剖析,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09詳解C++ 編寫String 的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)
這篇文章主要介紹了詳解C++ 編寫String 的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)的相關(guān)資料,這里提供實(shí)例幫助大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-08-08C語言實(shí)現(xiàn)線索二叉樹的前中后創(chuàng)建和遍歷詳解
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)線索二叉樹的前中后創(chuàng)建和遍歷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02基于Qt實(shí)現(xiàn)可拖動(dòng)自定義控件
這篇文章主要為大家詳細(xì)介紹了如何基于Qt實(shí)現(xiàn)可拖動(dòng)自定義控件,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2023-04-04C++ win系統(tǒng)如何用MinGW編譯Boost庫
這篇文章主要介紹了C++ win系統(tǒng)如何用MinGW編譯Boost庫問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12OpenCV實(shí)現(xiàn)圖像背景虛化效果原理詳解
相信用過相機(jī)的同學(xué)都知道虛化特效,這是一種使焦點(diǎn)聚集在拍攝主題上,讓背景變得朦朧的效果。本文將詳細(xì)介紹一些這一效果的實(shí)現(xiàn)原理以及代碼,需要的可以參考一下2022-03-03