链接、装载与库
对于多文件的开发过程来说,关于这一些东西我确实是欠缺的,正好有机会接触《程序员的自我修养——链接、装载与库》一书,初读也是感受颇深。就随着认知增长一点一点记录一些东西吧
一、关于Extern
在C/C++中声明一个外部变量需要用到extern关键字,而外部函数声明却是可以省略extern的,不需要额外添加关键字,在动态链接当中,将cpp编译为ELF/PE格式后将其置于调用其的cpp文件相同的路径之下,并保留头文件,利用编译器进行编译,以我不成熟的理解,可以想象它仍然是cpp文件,只不过先被处理成了二进制而已
了解了头文件的作用,其实动态链接的时候不用头文件也是可以的,可以将其内容直接加到,所以那些头文件里的函数声明其实是一个外部函数的声明,故而不应该在那个为止将函数定义出来。
假设有如下一种情况代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/*------myfun.h------*/
int exa = 5;
void myfun();
/*------myfun.cpp------*/
void myfun(){
......
}
/*------main.cpp------*/
int main(){
......
return 0;
}
在myfun.cpp成为so库的时候,其实int是被声明成这so的模块的全局变量,但当我们拿myfun.h使用的时候,它就变成了main.cpp这个模块里再次定义的东西了(没有extern),需要改。另外建议别在头文件里定义什么东西,否则会出现一些重复定义的问题。其实头文件对计算机而言没什么作用,她只是在预编译时在#include的地方展开一下,没别的意义了,其实头文件主要是给别人看的。
二、神奇的强弱符号
我们经常在编程中碰到一种情况叫符号重复定义。多个目标文件中含有相同名字全局符号的定义,那么这些目标文件链接的时候将会出现符号重复定义的错误。通常对于全局变量来说,初始化后均为强符号,未初始化为弱符号,弱符号在链接时候会被强符号替代,我们可以通过GCC的__attribute__((weak))
来定义任何一个强符号为弱符号。
对于它们,下列三条规则使用:
- 同名的强符号只能有一个,否则编译器报”重复定义”错误。
- 允许一个强符号和多个弱符号,但定义会选择强符号的。
- 当有多个弱符号相同时,链接器选择内存占用最大的那个。
所以说,我们可以通过定义自己的库函数是强符号,而用户使用的时候定义弱符号,以此来观察是否能够调用库函数,或者用户函数。太神奇了。
但是弱函数也不能胡乱使用,第三点规则已经说明了问题。
三、argc和argv[ ]
其中argc
是外部输入的参数个数,argv[ ]
是参数的字符串数组。即在命令行执行时后面跟着的参数。