这篇文章旨在帮助 C/C++ 程序员理解链接器在背后到底做了什么,在过去的这些年我已经向很多同事解释过同样的问题,所以,我决定是时候将它写下来,以帮助更多的人(我也不用再一一解释了)。
我所帮助的人中让我解释链接器到底干什么这个问题,一个典型的例子是遇到类似下面这样的链接错误:
g++ -o test1 test1a.o test1b.o
test1a.o(.text+0x18): In function `main':
: undefined reference to `findmax(int, int)'
collect2: ld returned 1 exit status
如果你的反应是“大概差不多是缺少 extern "C"
” 吧,那么你可能已经知道本篇文章中要介绍的所有东西了。
这节快速回顾一下一个 C 文件中有哪些不同的部分,如果下面的 C 文件示例中东西你都知道的话,你可以跳到下一节。
首先需要理解的是将声明(declaration)和定义(definition)区分开。定义是将一个名字与该名字的实现关联起来,这个可以是数据或者是代码:
- 变量的定义意味着编译器为该变量预留空间,有可能将某个特殊的值填入其中。
- 函数的定义意味着编译器为该函数生成代码。
声明 则是告诉 C 编译器某个东西(带有特定的名字)已经在程序的某个地方的定义已经存在了,可能在不同的 C 文件中。(注意定义也可以看作是一种声明)
对于变量,定义可以分为两类:
- 全局变量,存在与程序的整个生命周期内,通常可以在不同的函数中可以访问。
- 局部变量,仅在某个函数执行的时期内存在,也仅仅可以由该函数进行访问。