接上文
OK! Right now! Let's go!
今天我们来谈谈链接,什么是链接,C++链接实际上做什么的?
链接是一个过程,当我们从源C++文件转到实际的可执行文件(二进制文件)。第一阶段是编译源文件,一旦我们把文件编译好,就需要通过一个叫做链接的过程,现在链接的主要工作是找到每个符号和函数在哪里,并把他们链接起来。记住,每个文件被编译成一个单独的目标文件,他们彼此之间没有关系,这些文件不能交互。所以如果我们决定把我们的程序分割成多个C++文件,我们需要一种方法把这些文件连接在一起成一个项目,而这就是链接器的主要目的和要做的事情。
要记住我们要生成一段代码有两个阶段,一是编译,而是链接。如果只ctrl+F7(编译),如果F5(生成)那就是编译并链接,所以这两个操作可能会得到不同类型的错误。如果我们犯了语法错误,编译器会报错
这个代表链接,她告诉我们这个错误发生在链接阶段
我们可以看到配置类型是exe文件,这种文件必须要有某种入口点。一般默认是main函数,但实际我们可以更改这个函数名,也就是入口点不一定必须是一个叫main的函数。在链接器高级入口点选项可以看到我们可以指定一个自定义的入口点。
如果我们加上main函数可以看到成功运行生成了一个.exe文件
接下来我们看链接失败的几种情况:
我们可能会遇到一种错误,叫做未解决的外部符号unresolved external symbol,这就是当链接器找不到他需要的东西时发生的。
他认为在 某个地方有一个log函数,但这是链接的工作,就是找log函数的阶段。
如果我现在构建整个项目,你会看到实际上我们得到了一个错误
他告诉我们丢失了什么符号,他是Log函数,他甚至告诉我们在哪里引用了他(在Multiply函数中)
现在我们注释掉这个log函数,我们不去调用它,
如果我试着build下,没有错误,发生这种情况的原因是我从来没有调用过log函数,所以链接器不需要去链接这个log函数。
另一个有趣的是,
我注释了这一行,即我从来没有调用过Multiply函数,也就不会调用log函数了,如果我现在build我的项目
你会看到我仍然得到了一个链接错误,你可能会说why?!
我没有在任何地方调用Multiply函数,为什么他会抱怨链接错误,我们可不可以说这些没用的死代码一点意义都没有呢?
大错特错!因为在这个文件里,虽然我们不用Multiply函数,但技术上讲,我们在另一个文件中可能使用它。所以链接器确实需要链接它。
如果我们能告诉编译器,嘿这个Multiply函数,我只会在这个文件中使用它,不会在其他文件中使用它,我们可以去掉这种链接的必要性,因为Multiply从来不会被调用,也就是从不需要调用log函数,可以通过一个方法做到。
如果我把这个函数名称改回来,并修改了返回值类型
原因是我们的链接器要寻找一个名叫log的函数,她的返回值是void以及参数是const char* message。同样的函数名,返回值,参数。我们的链接器才会链接成功。
另一种链接错误很常见,就是我们有重复的符号,换句话说,我们的函数或变量,有相同的名字、两个名字相同的函数有相同的返回值和相同的参数。如果发生这种情况,我们就有麻烦了,不知道该链接到哪一个。
只编译这个Log.cpp文件就可以发现问题。
如果我们不写在一起,把一个写在math文件中
只编译他就不会发现问题但如果我们build整个项目,我们会得到一个链接错误,
当然以上错误太明显了
以下为一种不常发现的错误
这是因为#include头文件的作用,所以我们有几种解决方法:
①我们在Log.h文件中的Log函数前面加上static,之后log和math文件都会有自己版本的log函数
加上static后,它对任何其他的obj文件都不可见
现在我们build整个项目,ok了
②我们在Log.h文件中的Log函数前面加上inline,inline的意思是获取我们实际的函数体并将函数调用替换为函数体
变成下面这个
其他不变
③还有一种方法,就是把Log函数的定义移到一个翻译单元。因为现在的情况是这个log函数的定义列入了两个翻译单元(Log.cpp和math.cpp),这是导致错误的主要原因,我们可以把他搬到第三个翻译单元(这里因为有同名的文件,所以就放在Log.cpp中)
在工作结束以后,链接器需要带走我们所以的目标文件,并将他们链接在一起。他也将可能被拉进我们可能用到的其他任何库,例如C运行时库,如果有必要,C++的标准库,平台的api等等。从许多不同的地方链接是很正常的。还有很多不同类型的链接,静态链接和动态链接。
标签:文件,Log,函数,C++,链接,那些,我们,log From: https://blog.csdn.net/2401_87088772/article/details/142287035