轉載於:http://blog.csdn.net/lincoln_2012/article/details/50801080
項目中經常使用C和C++混合編程,那么,在調用對方接口時,總是不可避免地出現問題。為了讓雙方和諧地工作,就得用到extern "C"。
1 問題
在C++中,為了支持重載機制,在編譯時,要對函數的名字進行一些處理,比如加入函數的返回類型等來加以區別;在C中,只是簡單的函數名字而已。如函數void func(int i),C++會把它編譯成類似_fun_int或_xxx_funIxxx這樣的增加了參數類型的符號,這也是C++可以實現重載的原因;C則把該函數編譯成類似_fun的符號,C鏈接器只要找到該函數符號就可以鏈接成功,它假設參數類型信息是正確的。故而,關鍵問題是,C和C++在編譯時生成函數名字的方式是不同的。
2 方法
extern "C"是C++的特性,是一種鏈接約定,它並不影響調用函數的定義,即使做了該聲明,對函數類型的檢查和參數轉換仍要遵循C++的標准,而不是C。主要是為了解決C++在調用C函數庫時,用C++直接鏈接就會出現不能識別符號的問題,而用上extern "C"后,告訴C++編譯器要以C語言的方式編譯和鏈接函數,即直接使用函數名而不是一個經過處理的函數名。
3 示例
3.1 C++中調用C接口
代碼:
- /***** C頭文件c.h *****/
- #ifndef _C_H_
- #define _C_H_
- #ifdef __cplusplus /*C++編譯器包含的宏,例如用g++編譯時,該宏就存在,則下面的語句extern "C"才會被執行*/
- extern "C" { /*C++編譯器才能支持,C編譯器不支持*/
- #endif
- void C_fun();
- #ifdef __cplusplus
- }
- #endif
- #endif
- /***** C源文件c.c *****/
- #include "c.h"
- void C_fun()
- {
- /*dosomething*/
- }
- 功能:在文件cpp.cpp中調用文件c.c中的函數C_fun()
- /****** C++源文件cpp.cpp ******/
- #include "c.h"
- int main()
- {
- C_fun()
- }
編譯: g++ cpp.cpp c.c
3.2 C中調用C++接口
代碼:
- /**** C++頭文件 cpp.h *****/
- #ifndef CPP_H
- #define CPP_H
- extern "C" int add( int x, int y );
- #endif
- /**** C++源文件 cpp.cpp *****/
- #include "cpp.h"
- int add( int x, int y )
- {
- return x + y;
- }
- 功能:C文件中調用C++的接口
- /**** C源文件c.c *****/
- extern int add( int x, int y );
- int main( int argc, char* argv[])
- {
- }
編譯:gcc c.c cpp.cpp
3.3 C++中調用C庫的函數
代碼:
- /*C庫源文件: hello.c*/
- #include <stdio.h>
- void func()
- {
- printf("hello,world!\n");
- }
編譯:gcc --shared -o libhello.so hello.c
- /*C++源文件test.cpp中調用C庫的函數*/
- #include <iostream>
- #ifdef __cplusplus
- extern "C" { // 告訴編譯器下列代碼要以C鏈接約定的模式進行鏈接
- #endif
- void func();
- #ifdef __cplusplus
- }
- #endif
- int main()
- {
- func();
- return 0;
- }
編譯:g++ test.cpp -o test -lhello
3.4 C中調用C++庫的函數
1)C++庫代碼
- /*C++庫源文件hello.cpp*/
- #include <iostream>
- void funcpp()
- {
- std::cout << "hello, world" << std::endl;
- }
編譯:g++ --shared -o libhello.so hello.cpp
2)中間接口庫,對C++庫進行二次封裝
- /*中間接口庫 mid.cpp*/
- #include <iostream>
- void funcpp();
- #ifdef __cplusplus
- extern "C" { // 即使這是一個C++程序,下列這個函數的實現也要以C約定的風格來搞!
- #endif
- void m_funcpp()
- {
- funcpp();
- }
- #ifdef __cplusplus
- }
- #endi
編譯:g++ --shared -o libmid.so mid.cpp -lhello
3)C通過鏈接二次接口庫調用C++庫
- /*C源文件test.c*/
- #include <stdio.h>
- int main()
- {
- m_funcpp();
- return 0;
- }
編譯:gcc test.c -l mid -o test