C/C++代码的混合使用
一、extern "C"
C/C++的代碼要混合使用,肯定要用到extern "C"了。extern "C"暗示編譯器,被它修飾的內容使用C的鏈接風格,什么意思呢,直接上代碼:
1 //sample.cpp 2 3 void fun(int a) 4 { 5 } 6 7 void fun(int a, double b) 8 { 9 } 10 11 extern "C" void foo(int a) 12 { 13 }這里有三個函數,首先是重載的兩個fun函數,然后是用extern "C"修飾的foo函數。用g++編譯一下,然后查看下導出的符號:
發現了吧,兩個fun函數編譯后導出的符號是前綴"_Z3"加上函數名,再依次加上參數類型的簡寫。所以void fun(int a)變成了_Z3funi,void fun(int a, double b)變成了_Z3funid。這樣做是為了支持函數重載,即,只要參數不同就可以認為是不同的函數。而用extern "C"修飾的函數foo,編譯后導出的符號僅僅只是函數名。這就是C的鏈接風格,當然這樣函數重載也就沒辦法支持了。
用了extern "C",使得無論是C還是C++的代碼,編譯過后針對同一個函數使用相同的符號,這樣鏈接到一起的時候就不會報“undefined reference"了。實際使用時有兩種場合,要么是C++代碼調用C代碼,要么是C代碼調用C++代碼。
順便提一下,extern "C"只能寫在C++代碼中,C編譯器是不認的。
二、C++調用C
還是直接看示例代碼清晰明了:
1 //caller.cpp 2 3 #include <iostream> 4 5 using namespace std; 6 7 extern "C" void fun(void); 8 9 int main() 10 { 11 cout << "I'm caller.." << endl; 12 fun(); 13 } 1 //fun.c 2 3 #include <stdio.h> 4 5 void fun(void) 6 { 7 printf("This is C function \"fun()\"\n"); 8 }這樣兩個文件,簡單編譯運行一下:
?
當然,如果把extern "C" void fun(void);放到頭文件中風格會更好。本人比較懶,這里的簡單示例就不按規矩寫了。
三、C調用C++
這部分寫了兩個例子,首先是調用C++的普通函數,然后是調用類成員函數。
同樣看代碼,不過,先看一下被調用者C++代碼:
1 //fun.cpp 2 3 #include <iostream> 4 using namespace std; 5 6 void fun(int a) 7 { 8 cout << "This is cpp function \"fun(" << a << ")\"" << endl; 9 } 10 11 void fun(int a, double b) 12 { 13 cout << "This is cpp function \"fun(" << a << ", " << b << ")\"" << endl; 14 } 15 16 extern "C" void foo(int a) 17 { 18 cout << "This is cpp function \"foo(" << a << ")\"" << endl; 19 } 20 21 extern "C" { 22 23 void fun_i(int a) 24 { 25 fun(a); 26 } 27 28 void fun_d(int a, double b) 29 { 30 fun(a, b); 31 } 32 33 }這里有5個函數,兩個重載的fun函數,剩下三個函數foo, fun_i, fun_d全都用extern "C"修飾了,導出給C代碼調用。關于extern "C"的兩種寫法,一目了然,我就不解釋了。這里的fun_i和fun_d只是把fun的兩個重載版本分別包裝了一下,因為C是沒有函數重載的概念的。foo沒有重載,所以也沒有包裝函數。事實上,如果知道C++編譯器命名符號的規則(本文一開始已討論過),不用extern "C",不用包裝函數,直接使用符號調用也是可以的。這種方式在下面caller.c中也有示范:
1 //caller.c 2 3 #include <stdio.h> 4 5 int main(int argc, const char *argv[]) 6 { 7 printf("I'm C caller...\n"); 8 9 fun_i(1); 10 fun_d(2, 2.1); 11 foo(3); 12 13 _Z3funi(4); 14 _Z3funid(5, 5.1); 15 16 return 0; 17 }編譯運行:
可見,用包裝函數調用和用符號調用都可以工作。我這里鏈接了libstdc++庫,因為我是用gcc編譯的,如果用的是g++,libstdc++是會默認鏈接的。這就涉及到項目主體是C還是C++的問題了,如果主體是C代碼,必須用gcc編譯,但是又引用了C++寫的庫,這時候鏈接一定要加上libstdc++。反之,如果主體是C++,用g++編譯不會有類似的問題。
?
下面再提供一個用C代碼調用C++類成員函數的例子,用包裝函數:
1 //fun.cpp 2 3 #include <iostream> 4 using namespace std; 5 6 class shit 7 { 8 public: 9 shit(){} 10 ~shit(){} 11 void happen(); 12 }; 13 14 void shit::happen() 15 { 16 cout << "Holy shit!!" << endl; 17 } 18 19 extern "C" 20 void run() 21 { 22 shit fresh_shit; 23 fresh_shit.happen(); 24 } 1 //caller.c 2 3 #include <stdio.h> 4 5 int main(int argc, const char *argv[]) 6 { 7 printf("I'm C caller...\n"); 8 run(); 9 10 return 0; 11 }編譯運行:
轉載于:https://www.cnblogs.com/suosuopuo/p/3388748.html
總結
以上是生活随笔為你收集整理的C/C++代码的混合使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第七章:暴力求解法。第二部分
- 下一篇: QTP自动化测试框架的基础知识