这个系列进行到这里,我们完成了main方法的本质,命令行参数怎么解析,编译过程,指针的反向思考,以及extern的用途,静态库动态库的拆解,可变参数,static的妙用,inline的内联意义,const为啥还能改?
这一节我们来看下一个好玩的内容,就是C和C++的混合编程,我们来逐步拆解,就能够明白。
回顾下之前的内容,我们的源码,会经历预处理,编译,汇编,链接,而C与C++最终相遇,要解决的问题,会在链接过程遇到,我们来看下具体代码:
add.c
对应的头文件:add.h
然后hello.cpp,这里我们把后缀改成cpp了,代码如下:
引用了add函数,那么我们编一下,看看结果吧。
gcc-oadd.o-cadd.c
gcc-ohello.o-chello.cpp
gccadd.ohello.o-ohello
链接出错,我们看下出错信息:
可是我们明显链接了add.o,那么原因是什么呢?我们揭开hello.o,一探究竟。我们使用readelf-shello.o,来看下它的符号表,
发现了一个神奇的地方,UND未定义,后面跟着是个_Z3addii,这个跟我们add.o里面导出去的符号不一致,所以链接失败了。
这里就是这一节要讲的,cpp编译生成的目标文件中的符号定义,跟c生成出来的有区别,符号命名的方式不一样。这里是add.o里面add符号,可以发现不一样。
那么今天的主角就出现了,extern"C",它在解决什么问题?它在解决符号该如何去生成,这里指定让cpp中引用的对应函数,能够以C语言的方式去编译,汇编。
于是,我们就可以这样子处理下,把add.h修改下:
这里我们让引用它的地方,按照C语言的方式生成符号,我们这样子重新编译:
gcc-ohello.o-chello.cpp
gccadd.ohello.o-ohello
发现编译过了,也能运行了。是不是发现很简单?这就是我想讲的内容,抽丝剥茧,从本质解决问题出发,来剖析每个语法,关键字的意义,这样子才是真正的去思考,掌握语言的魅力!
这里想说的是,extern"C"这个玩意C源码引用是无法解析的,因为这个是C++特定的,所以这个头文件要做一个修订,
我们补充一个定义,用这个包含起来,这个定义是gcc在处理c++的源码时候,会去定义的一个值。而处理C源码不定义,自然就绕过了extern"C".
那么同样的道理,如果是C想调用C++的呢?C++的函数前面标记extern"C",就会变成C可以调用的。
当然这里还想说的是,C++的对外,extern"C",一般是独立出去,单独的一个实现,用来做C和C++内部的桥梁。
好了,今天就讲到这里,相信大家一下子也听明白了。下一节我们来讲下volatile关键字的用法,以及它的作用,C相关的关键点,说了一部分,我们讲完这些,就会进入项目实战,大家