为了描述清楚C和C++之间区别,我们先创建两个源文件.c和.cpp
.c文件:
.cpp文件:
运行出来结果如图:
会出现错误,无法解析的外部符号,在main中引用
为什么呢?因为在.cpp文件中,sum函数声明是对函数的引用,生成的符号是“UND”的,产生的符号是sum_int_int的,
在.c文件中,sum是在.text段,生成的符号是sum,两个符号不同,
在C++里面调用C的接口,由于符号不同,我们给函数外面加了extern "c",如下:
此时,运行成功。
再来看,下面图中.c和.cpp文件中代码如图所示:
既然有extern "C"可以实现C++调用C语言,那么我们有些人可能会想那有没有extern "C++"之类可以实现C语言调用C++呢?答案是否定的!为什么呢?我们都知道C语言比C++出来的早,一般都是后者要兼容前者的,所以就不会有extern "C++"之类的。
既然extern 只能在C++中使用,那么如何实现C语言调用C++呢?我们可以通过下面的方法实现,即在.cpp文件中源代码直接包含在extern "C"里面,这样一来.cpp是按照C++的这样就可以了。如图:
我们经常可以看到类似于下面这样的代码,这种写法是什么意思呢?如果没有这个宏意味着你是用C语言编译器编写,代码本身就是C语言所以没有影响,如果你是用C++编译器编写的,也就意味着有这个宏,有这个宏的话,它就会展开extern "C",生成的符号还是C语言的符号,这段代码可以保证,不管你用C还是C++编译器去编译,生成的都是C语言的符号,
于是又有一个问题出现了,如果是在公司里的话,你要用别人的函数,一般别人是不会给你源代码的,只会给你提供接口,所以上面的C调用C++这种写法一点都不现实。
我们一般写代码的时候会包含头文件:#include ,里面会调用printf和scanf等函数,这些函数在#include 里面只有声明,那么,它们的定义在哪里呢?定义在libc.so里面,这是动态链接库,在运行的时候链接。
那么静态链接和动态链接的区别是什么?
静态链接就是两步,
在windows下静态链接一般都是链接的 *.lib ,动态链接链接的是*.dll
在linux下静态链接都是链接的*.a,动态链接都是链接的*.so
静态链接都是在编译的时候链接,也就是在可执行文件之前进行链接,所以在静态链接的时候可执行文件没有生成,静态链接完了,可执行文件才生成。
静态库里面提供了很多函数的定义,比如printf,scanf,puts,gets,等,你只用了puts就生成你的可执行文件,但是其他函数的定义还是存在于你的代码中的,占可执行文件的大小。
动态链接不一样,是在运行了之后才链接,动态链接的时候,可执行文件已经生成并且运行了,
动态链接的好处就显而易见了,动态库里面有很多函数,你用到哪个才会链接到哪个,不用的话,那些函数的代码段就不会占用你的可执行文件的大小。好处就是减少可执行文件的大小,缺点是:在运行的时候进行链接没有静态链接快。因为静态链接在运行之前就已经链接好了,运行的时候直接执行就好了,当然,动态链接更主要的是在各个进程之间进行数据共享。
一般我们给别人代码,都是给*。h和*.so,头文件里面只有函数的声明,库里面才是函数真正的定义,库里面的东西你是改不了的。
那么,就是下面这幅图中,C++调用C语言该如何做呢?
这种呢,是很方便的,也就是C++调用C语言是很方便的,直接在声明处extern "C"就好了,
如果库里面有很多函数需要调用,直接这么写就好了,能不能看到C的源代码并不重要。
那么,反过来,C调用C++就不一样了(如下图),为什么不一样呢?刚才是把C++里面的代码括到extern "C"里面,现在你根本看不到C++里面的源代码,所以括不了。
那么当C++以库的形式提供代码的时候,C该如何调用C++呢?
《程序员的自我修养—链接、装载与库》文中有一句话这么说“计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决”,于是,我们遇到的这个问题便可以通过增加一个中间文件来实现。
如下图:
通过中间文件,把C++封装成C语言的接口,就可以调用了。