再論extern “C”:C++代碼調用C代碼

 

我昨天分享了一篇文章:C++項目中的extern “C” {} ,作者網址是:http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html。後來感覺這篇文章中有的地方和自己的認識不同。就重新寫一篇吧。重點在C++代碼調用C代碼的方面和C代碼調用C++代碼方面。
先說兩點:
1.VC編譯器既是一個C編譯器,又是一個C++編譯器。
   默認情況下,對於後綴名爲.c的文件,VC編譯器cl會使用C的方式去編譯;對於後綴名爲.cpp的文件,VC編譯器會使用C++的方式去編譯。
   還可以顯式指定是按照C的方式還是C++的方式去編譯源文件。調出VC編譯器cl,敲入命令 cl /? ,就可以看到了。
      /Tc<source file> compile file as .c
      /Tp<source file> compile file as .cpp
      /TC compile all files as .c
      /TP compile all files as .cpp
2.昨天分享的那篇文章中有這樣一句話:注意:extern "C"指令中的C,表示的一種編譯和連接規約,而不是一種語言。C表示符合C語言的編譯和連接規約的任何語言,如Fortran、assembler等。這裏我感覺應該這樣說:extern "C"指令中的C,表示的一種編譯規約和連接約,而不是一種語言。具體來說,對於extern “C”修飾的函數來說,是一種編譯規則,告訴編譯器按照C的方式來編譯這個函數;對於其它的函數來說,是一種鏈接規則,告訴其它函數按照C的方式去鏈接這個被extern “C”修飾的函數。

好了,來看例子吧。先看C++代碼調用C代碼的例子。以昨天分享的代碼爲例:

/*CHeader.h*/
#ifndef C_HEADER
#define C_HEADER

extern void print(int i);

#endif C_HEADER

/*CHeader.c*/
#include <stdio.h>
#include "cHeader.h"
void print(int i)
{
    printf("cHeader %d\n",i);
}

/*C++.cpp*/
extern "C"{
#include "cHeader.h"
}

int main(int argc,char** argv)
{
    print(3);
    return 0;
}

總共三個文件:CHeader.h,CHeader.c和C++.cpp。手工編譯CHeader.c和C++.cpp,命令如下:
cl /c /Tc CHeader.c
cl /c /Tp C++.cpp
我們可以使用dumpbin工具來查看一下由CHeader.c生成的CHeader.obj文件,命令如下:
dumpbin /symbols CHeader.obj
如下圖所示:

可以看到,print函數被編譯爲_print。然後使用link將CHeader.obj和C++.obj鏈接起來,命令如下:
link CHeader.obj C++.obj
生成CHeader.exe。執行一下,會輸出“cHeader 3”,運行正常。
那麼,如果使用C++的方式編譯CHeader.c文件,又會怎麼樣。我試了一試,如下命令:
cl /c /Tc CHeader.c
cl /c /Tp C++.cpp
link CHeader.obj C++.obj
編譯都通過,但是鏈接不成功,錯誤。如下圖所示:

提示說找不到_print這個symbol。因爲在C++.cpp文件中,我們使用了extern “C” ,認爲print函數是按照C的方式編譯的,會編譯成_print,但實際上我們編譯CHeader.c文件的時候,是按照C++的方式編譯的,沒有把print函數編譯成_print。我們可以再次使用dumpbin工具查看一下:

看到了吧,使用C++方式將print函數編譯成了?print@@YAXH@Z這個symbol,這樣,鏈接的時候當然找不到_print這個symbol了。
算了,今天太晚了,下次再說C代碼調用C++代碼的例子吧。其實都差不多的。

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