从error LNK2019引出C++程序的构建过程

最近在写一个C++静态库,就叫a.lib吧,a.lib编译一切正常,另一个程序b.exe使用a.lib,但在编译b.exe时,编译器报“error LNK2019: unresolved external symbol “”public CMyClass::AddField“””错误。因为之前没写过静态库程序,对于a.lib编译正常,但b.exe编译不通过,首先想到的是a.lib是不是要向动态库那样在定义CMyClass时前面加上__declspec(dllexport),但看了一下a.exe在调用CMyClass其它成员函数时却没有问题。这时定位到AddField的声明,按F12想跟到实现看看,编辑器却没有跳转,这时才恍然大悟,之前写AddField只写出了声明,没有去实现该函数,但是在a.lib内部也有其它地方调用了AddField,在编译时为何没问题?这就要涉及到C++的编译过程了。

C++程序的构建分为四个步骤:预编译、编译、汇编、链接。

每个步骤将文件编译成别的格式,如下:

步骤未编译预编译编译汇编链接
文件tool.h、tool.cpp、test.cpp

tool.i、test.i

tool.s、test.stool.o、test.oprojectname.exe

1.预编译:

预编译过程主要做4件事:

①展开头文件

②宏替换

③条件编译

④去掉注释

2.编译:

将代码转成汇编代码,并且在这个步骤中做了两件很重要的工作:

①编译器在每个文件中保存一个函数地址符表,该表中存储着当前文件内包含的各个函数的地址;

②因为这步要生成汇编代码,即一条条的指令,而调用函数的代码会被编译成一条call指令,call指令后面跟的是jmp指令的汇编代码地址,而jmp指令后面跟的才是“被调用的函数编译成汇编代码后的第一条指令”的地址,但是给call指令后面补充上地址的工作实在链接的时候才做的事情;

3.汇编:

将汇编代码转成机器码;

4.链接

编译器将前面产生的多个.o文件链接到一起生成一个.exe可执行文件;

但是在这个过程中,编译器做的一个重要的事情就是讲每个文件中call指令后面的地址补充上;方式是从当前文件的函数地址符表中开始找,如果没有,继续从别的文件的函数地址符表中找,找到后填补在call指令后面,如果找不到,则链接失败。


重温了C++的编译过程,我猜测a.lib编译并没有完全包含这四步,至少没有进行到链接这一步。对于静态库a.lib的使用,b.exe在链接阶段将自己生成的.o目标文件与a.lib进行链接,最终生成可执行文件b.exe。既然a.lib可与.o文件进行链接,那么静态库的格式必定与.o是兼容的。

继续查资料,看到这篇《静态库和动态库的区别》有这样一句话“静态库可以简单看成是一组目标文件(.o/.obj文件的集合),即很多目标文件经过压缩打包后形成的一个文件,类似delphi的.dcp文件”。这样就很明了了,静态库在编译时只进行到汇编这一步,并不进行链接,自然也不会检查某个被调用的函数是否有具体的实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值