canmeng50401的专栏

统计

留言簿

阅读排行榜

评论排行榜

再论extern “C”:C++代码调用C代码 .

我昨天分享了一篇文章:C++项目中的extern “C” {} ,后来感觉这篇文章中有的地方和自己的认识不同。就重新写一篇吧。重点在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代码的例子。以昨天分享的代码为例:

 1/*CHeader.h*/
 2#ifndef C_HEADER
 3#define C_HEADER
 4
 5extern void print(int i);
 6
 7#endif C_HEADER
 8
 9/*CHeader.c*/
10#include <stdio.h>
11#include "cHeader.h"
12void print(int i)
13{
14    printf("cHeader %d\n",i);
15}

16
17/*C++.cpp*/
18extern "C"{
19#include "cHeader.h"
20}

21
22int main(int argc,char** argv)
23{
24    print(3);
25    return 0;
26}

总共三个文件: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++代码的例子吧。其实都差不多的。

posted on 2011-11-14 23:49 纪灿萌 阅读(403) 评论(0)  编辑 收藏 引用 所属分类: 一些软件的应用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理