很久以前写的了,一直忘了贴上来了~今天看ORACLE烦了,有时间贴上来~ 前言: 昨天脑子一热问了一个很easy的问题,结果把自己都弄糊涂了,惹来高手们的痴笑,回头想一想是个很简单的问题,却想了那么多,晕!今天做个总结吧!(:---
链接指示符(linkage directive) extern “C” 的问题:
如果我们在自己的程序中要用到其它语言所编写的函数,那么我们的调用函数就必须告诉编译器使用不同的要求。 因为函数在函数名的生成,参数的入栈,栈的清空等等方面与所使用的语言是密切相关的。 Linkage director 告诉编译器,该函数是用其他的程序设计语言编写的。Linkage director 有两种形式: 1.单一的语句(single statement)形式: extern “C” void exit(int ); 2.复合的语句(compound statement)形式: extern “C” { int printf(const char *…..); int scanf(const char *..); } 或: extern “C” { #include <cmath> }
这里{ }只是一个分割符,用来说明在那个链接指示符用在那些声明上,没有其它的意义了,也就是说在花括号内声明的函数是可见的了!不要胡思乱想!
extern “XX”可以告诉编译器,该函数是用其它语言来编写的,但强制这些函数采用XX语言的方式进行编译。
举个例子说吧!
C接口的方法: C中调用C++函数: 生成一个工程叫demo 加入一个demo.c 内容如下:
int add(int a,int b );//有无都可
int main() { int i=add(3,2);
printf("i=%d",i); return 0; } 再加入一个add.cpp,(注意扩展名,强制控制台生成两种文件类型)内容如下:
int add(int a,int b) { return a+b; } 如果这样编译的话,会产生下面的错误:Linking... demo.obj : error LNK2001: unresolved external symbol _add Debug/demo.exe : fatal error LNK1120: 1 unresolved externals Error executing link.exe 根据提示说是没有找到-add,可是我明明定义了!. 为了搞清这个这个问题,就要搞清楚到底C的函数和CPP的函数在编译之后,会变成什么样子! C++支持重载,C中不支持,而C++怎么区分这些重载函数呢,究竟调用那下一个呢?C++会能过不同的参数来选择不同的 具有相同名称的不同的实现函数的调用。C++函数被编译以后,函数会附带一些附加的参数信息! 我们以实事说话: 在add.cpp中再加入一个同名函数实现重载 float add(float fa,float fb) { return fa+fb; } int add(int a,int b) { return a+b; } 单独编译此文件没有问题! 输出一个map文件,找到add函数: Address Publics by Value Rva+Base Lib:Object
0001:00000030 _main 00401030 f demo.obj 0001:00000080 ?add@@YAMMM@Z 00401080 f add.OBJ 0001:000000b0 ?add@@YAHHH@Z 004010b0 f add.OBJ 明白了吧! 精华都在这里了! 提示说找不到_add,原来是在C语言被编译过程中,自动加上了下画线了! 看看main就知道了! 而在C++中,函数被扩展了,?add@@YAMMM@Z,前面两个@相当于左括号,后面一个相当于右括号,中间的就是用来表示参数的了!简单吧! 两个重载函数使用了不同的参数,一个是整数,一个是浮点数,当这两个函数进行连接时,在相应的C++的连接过程中,编译器也会以编译出来的名字到对应的OBJ文件中查找。在C++编译中,会把参数的类型,名字和函数的名字组合成为一个新的函数,这样就和程序定义的函数名这相一致!
现在在看看错误提示,我们的输出文件中也找不到这个_add,所以程序不可能连接上。知道原因就解决吧! 最直接的方法就是修改C++文件的编译结果,让它产生一个对应C的函数名字,也就是按C的方法来生成对应的函数。 在C++的头文件中加入: extern "C" int add(int a,int b); extern “C” 语句的作用就是把C++函数按C约定编译! 运行,OK!
Address Publics by Value Rva+Base Lib:Object
0001:00000030 _main 00401030 f demo.obj 0001:00000080 ?add@@YAMMM@Z 00401080 f add.obj 0001:000000b0 _add 004010b0 f add.obj 变了吧!
那么C++中调用C呢! 由于两者之间的关系,C++中可以说是直接调用就可以了!不过这是有条件的! 把demo.c改成: int substract(int a,int b) { return a-b; } void hello() { printf("hello"); } add.cpp改为: void hello(); int substract(int a,int b);
int main() { hello(); int c=substract(4,1); printf("c=%d",c); return 0; } 编译运行,出现了上次一样的错误:
加上 extern "C" { void hello(); int substract(int a,int b); }
就OK了! 这是两者的map 比较: 0001:00000030 _substract 00401030 f demo.obj 0001:00000060 _hello 00401060 f demo.obj
0001:00000030 _substract 00401030 f demo.obj 0001:00000060 _hello 00401060 f demo.obj
发现是一样的! 问题在于你在add.cpp前面加入了: void hello(); int substract(int a,int b); 这样就把两个函数编译成了C++方式,去找它的实现代码的时候,肯定出错了! 而在C调用C++的时候, int add(int a,int b );加与不加,系统只是会给出一个提示, 这或许就是C++强的地方吧! 把错误消灭在初期!
Extern “C”是唯一被保证由所有的C++实现都支持的。 以上代码在VC6。0+WINXP(倒版)下调试通过!
|
|
来自: 昵称16235376 > 《C 》