在上一篇文章中(gcc编译器常识)提到关于gcc编译器在编译程序经过了4个步骤,其中最后一个步骤为:链接。
其中在C/C++中链接可分为两种,分别是静态链接和动态链接。
静态链接是指程序在编译阶段把程序所需要的执行代码直接拷贝到调用处。
优点:比较容易理解,在程序发布时不需要格外的依赖库,程序可以独立运行。
缺点:因为每次调用都通过代码拷贝的方式,所以会导致程序体积比较大。
动态链接是指程序在编译阶段并不把代码直接拷贝到调用处,而是通过记录一些列符号或者参数,在程序运行时期通过这些信息发送给操作系统,操作系统根据这些信息找到程序所需要的执行代码加载到内存,以供调用。
优点:可以多个程序共享同一段代码,而不需要拷贝到每一个调用处。
缺点:由于是在运行时才加载,所以会影响到程序的执行性能。
以下采用Linux平台,编写静态链接和动态链接的相关代码,以供理解。
静态链接:
/*tests.h*/
#ifndef _TEST_S_H
#define _TEST_S_H
void tests(char *str);
#endif
/*tests.c*/
#include <stdio.h>
#include "tests.h"
void tests(char *str)
{
printf("static way load:%s\n",str);
}
把以上代码打包成一个静态的库文件。
gcc -c tests.c -o tests.o
ar cqs libtests.a tests.o
ar 命令是一个把文件打包库文件的工具,cqs 是参数,静态库是以 .a 为后缀、以 lib开头的文件。
此处把 test.h 和 test.c打包成一个名为 libtests.a 的静态库文件。
main程序:
/*main.c*/
#include <stdio.h>
#include "tests.h"
int main(void)
{
char *str = "Hello World!";
tests(str);
return 0;
}
编译main程序加载静态库 libtests.a
gcc -o test main.c -L. -ltests
-l:表示所需链接的库文件,其后跟‘tests’表示为库 libtests.a 或者 libtests.so。
运行结果为
./test
static way load:Hello World!
动态链接:
/* testd.h */
#ifndef _TEST_D_H
#define _TEST_S_H
void testd(char *str);
#endif
/* tests.c */
#include <stdio.h>
#include "testd.h"
void testd(char *str)
{
printf("dynamic way load:%s\n",str);
}
把以上代码打包成动态链接库。
gcc -shared testd.c -o libtestd.so
-shared:表示打包成动态链接库。
动态链接库以.so后缀、‘lib’开头命名。
生成动态链接库后需要把库文件复制到 /lib 目录下,否则程序在加载的时候无法找到该动态链接库。
main 程序:
/* main.c */
#include <stdio.h>
#include "testd.h"
int main(void)
{
char *str = "Hello World!";
testd(str);
return 0;
}
编译main程序加载libtestd.so动态链接库。
gcc main.c -o testd -L. -ltestd
-L 和 -l 参数的意义和前面的一样。
运行结果为:
./testd
dynamic way load:Hello World!
注意:
如果含有同名的两个静态链接库(.a 后缀)和动态链接库(.so 后缀),在编译main程序时,会优先加载动态链接库。
若想强制程序加载静态链接库,需要加上 ‘-static’ 参数指定。