#ifdef __cplusplus extern "C" { #endif”的定義

看一些程序的時候老是有:

“#ifdef __cplusplus
extern "C" 

{
#endif" 的定義,搞搞清楚是怎麼回事:

Microsoft-Specific Predefined Macros
__cplusplus Defined for C++ programs only. (注意這裏是雙下劃線__)
意思是說,如果是C++程序,就使用
extern "C"{
而這個東東,是指在下面的函數不使用的C++的名字修飾,而是用C的名字。

The following code shows a header file which can be used by C and C++(下面的頭文件可以被 C 或者 C++調用)

client applications:
// MyCFuncs.h
#ifdef __cplusplus
extern "C" { 

//only need to export C interface if used by C++ source code

#endif

__declspec( dllimport ) void MyCFunc();
__declspec( dllimport ) void AnotherCFunc();

#ifdef __cplusplus
}
#endif

當我們想從C++中調用C的庫時,(注,驅動是用C寫的,連new、delete也不能用,鬱悶)不能僅僅說明 一個外部函數,因爲調用C函數的編譯代碼和調用 C++函數的編譯代碼是不同的。如果你僅說明一個外部函數, C++編譯器假定它是

C++的函數編譯成功了,但當你連接時會發現很可愛的錯誤。
解決的方法就是指定它爲C函數: 
extern "c" 函數描述 
指定一羣函數的話: 
extern "C"


n個函數描述 


如果想 C 和 C++ 混用的話: 
#ifdef _cplusplus 
extern "C"{ 
#endif 
n個函數描述 
#ifdef _cplusplus 

#endif

extern "C"表示編譯生成的內部符號名使用 C 約定。


      C++支持函數重載,而C不支持,兩者的編譯規則也不一樣。函數被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函數的原型爲: void foo( int x, int y ); 該函數被C編譯器編譯後在符號庫中的名字可能爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不 同,但是都採用了相同的機制,生成的新名字稱爲“mangled name”)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。下面以例子說明,如何 在C++中使用C的函數,或者在C中使用C++的函數。


//C++引用C函數的例子
//test.c
#include <stdio.h>
void mytest()
{
printf("mytest in .c file ok\n");
}


//main.cpp
extern "C"
{
void mytest();
}


int main()
{
mytest();
return 0;
}


//在C中引用C++函數
在C中引用C++語言中的函數和變量時,C++的函數或變量要聲明在extern "C"{}裏,但是在C語言中不能使用extern "C",否則編譯出錯。
//test.cpp
#include <stdio.h>
extern "C"
{
void mytest()
{
printf("mytest in .cpp file ok\n");
}
}


//main.c
void mytest();
int main()
{
mytest();
return 0;
}



綜合使用
一般我們都將函數聲明放在頭文件,當我們的函數有可能被C或C++使用時,我們無法確定是否要將函數聲明在extern "C"裏,所以,我們應該添加
#ifdef __cplusplus
extern "C"
{
#endif
//函數聲明
#ifdef __cplusplus
}
#endif


如果我們注意到,很多頭文件都有這樣的用法,比如string.h,等等。
//test.h
#ifdef __cplusplus
#include <iostream>
using namespace std;
extern "C"
{
#endif
void mytest();
#ifdef __cplusplus
}
#endif


這樣,可以將mytest()的實現放在.c或者.cpp文件中,可以在.c或者.cpp文件中include "test.h"後使用頭文件裏面的函數,而不會出現編譯錯誤。
//test.c
#include "test.h"
void mytest()
{
#ifdef __cplusplus
cout << "cout mytest extern ok " << endl;
#else
printf("printf mytest extern ok n");
#endif
}


//main.cpp
#include "test.h"
int main()
{
mytest();
return 0;
}

extern "C" 的用意 
前些天,編程序是用到了很久以前寫的C程序,想把裏面的函數利用起來,連接發現出現了找不到具體函數的錯誤:

以下是假設舊的C程序庫

C 的頭文件

/*-----------c.h--------------*/

#ifndef _C_H_

#define _C_H_extern

  int add(int x, int y);#endif


//C的源文件

/*-----------c.c--------------*/

int add(int x, int y){ return x+y;}


//C++的調用

/*-----------cpp.cpp--------------*/

#include "c.h"

void main()

{

add(1, 0);

}

這樣編譯會產生錯誤cpp.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z),原因是找不到add的目標模塊這才令我想起C++重載的函數命名方式和C函數的命名方式,讓我們回顧一下:C中函數編譯 後命名會在函數名前加以"_",比如add函數編譯成obj文件時的實際命名爲_add,而c++命名則不同,爲了實現函數重載同樣的函數名add因參數 的不同會被編譯成不同的名字

例如
int add(int , int)==>add@@YAHHH@Z,

float add(float , float )==>add@@YAMMM@Z,

以上是VC6的命名方式,不同的編譯器會不同,總之不同的參數同樣的函數名將編譯成不同目標名,以便於函數重載是調用具體的函數。

編譯cpp.cpp中編譯器在cpp文件中發現add(1, 0);的調用而函數聲明爲extern int add(int x, int y);編譯器就決定去找add@@YAHHH@Z,可惜他找不到,因爲C的源文件把extern int add(int x, int y);編譯成_add了;爲了解決這個問題C++採用了extern "C",這就是我們的主題,想要利用以前的C程序庫,那麼你就要學會它,我們可以看以下標準頭文件你會發現,很多頭文件都有以下的結構

#ifndef __H

#define __H

#ifdef __cplusplus

extern "C" 

{

#endif

extern int f1(int, int);

extern int f2(int, int);

extern int f3(int, int);

#ifdef __cplusplus

}

#endif

#endif


 /*__H*/如果我們仿製該頭文件可以得到

#ifndef _C_H_

  #define _C_H_

#ifdef __cplusplus

extern "C" 

{

#endif

extern int add(int, int);

#ifdef __cplusplus

}

#endif

#endif 


/* _C_H_ */ 

/*-----------c.c--------------*/
int add(int x, int y)

{
return x+y;
}

這時源文件爲*.c,__cplusplus沒有被定義,extern "C" {}這時沒有生效對於C他看到只是extern int add(int, int);add函數編譯成_add(int, int);

而編譯c++源文件

/*-----------cpp.cpp--------------*/
#include "c.h"
void main()
{
add(1, 0);
}
這時源文件爲*.cpp,__cplusplus被定義,對於C++他看到的是extern "C" {extern int add(int, int);}編譯器就會知道 add(1, 0);調用的C風格的函數,就會知道去c.obj中找_add(int, int)而不是add@@YAHHH@Z;這也就爲什麼DLL中常看見extern "C" {},windows是採用C語言編制他首先要考慮到C可以正確調用這些DLL,而用戶可能會使用C++而extern "C" {}就會發生作用



該博客轉自:http://blog.csdn.net/u013467442/article/details/42681615?ref=myread

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章