每个.cpp文件被编译成.obj文件(翻译单元),但是这些文件是不能交互的,这时需要link工作,使各文件结合在一起。
link的工作:找到每个符号和函数在哪里,并连接起来。每个文件都需要link,因为有main函数。
示例:
当只编译时,程序没有报错,接下来我们试试link。
link时(bulid->编译 + link),就会报错显示为main函数的问题
看错误的开头是LNK的说明是link阶段发生的错误,如果是语法错误实际上错误的开头是C,证明是编译阶段的错误。
错误:未解决的外部符号 unresolved external symbol
错误原因1:link找不到它需要的东西
当我们把log函数写成logr时,编译不会报错,但是link会报错,因为只有在link阶段会去寻找具体的函数体,而编译阶段只需要声明。
编译成功
link阶段报错显示无法解析的外部符号Log
但是当注释掉log函数build成功了,因为在这个函数中根本没使用到log函数,link也不会去找它
另一个有趣的现象是,即使在main函数中没有调用Log函数,仅是在函数体中使用Log函数,仍然会报错,原因是即使在这个main函数中你可能会没用到,但是link会认为你在其他cpp文件中可能会用到。
如果你想声明此函数只会在这个文件中生效,则使用static方法,并且你没使用它,则link阶段不会报错。但是一旦你使用了该方法,程序仍然会报错。
当返回值,参数不一致时,link也会报错。
错误原因2:出现了两个相同的东西
因为link不知道该link到那个地方
此时,直接发生编译错误,显示函数已经有主体,因为在同一个文件下,此时还没link。
当改到不同文件下,编译就可以通过。
再看一种不明显的错误:
此时,log函数只被定义了一次,再头文件里,其他两个cpp文件只是调用,link阶段仍然发生了错误,这时问题就出现再头文件上,因为编译器处理头文件仅仅是copy,因此在两个cpp文件里都对Log函数进行了定义。
解决方法一:将头文件的函数定义为static,这样两个cpp文件就有了自己版本的Log函数,对其他文件不可见。
解决方法二:将头文件的函数定义为inline,表示为将调用函数替换为函数体
此时不涉及Log函数的调用
解决方法三:将头文件只改成声明,新建一个cpp文件完成Log函数的定义。
这样在其他文件调用头文件时就不会有Log函数的定义,而link只会指向实现Log函数的cpp文件里