Linux下C编程基础之:gcc编译器
(4)链接阶段。
在成功编译之后,就进入了链接阶段。这里涉及一个重要的概念:函数库。
读者可以重新查看这个小程序,在这个程序中并没有定义“printf”的函数实现,且在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?最后的答案是:系统把这些函数的实现都放到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到libc.so.6函数库中去,这样就能调用函数“printf”了,而这也正是链接的作用。
函数库有静态库和动态库两种。静态库是指编译链接时,将库文件的代码全部加入可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名通常为“.a”。动态库与之相反,在编译链接时并没有将库文件的代码加入可执行文件中,而是在程序执行时加载库,这样可以节省系统的开销。一般动态库的后缀名为“.so”,如前面所述的libc.so.6就是动态库。gcc在编译时默认使用动态库。
完成了链接之后,gcc就可以生成可执行文件,如下所示。
[root@localhostgcc]#gcchello.o–ohello
运行该可执行文件,出现的正确结果如下。
[root@localhostgcc]#./hello
Hello!Thisisourembeddedworld!
3.3.2gcc编译选项分析
gcc有超过100个可用选项,主要包括总体选项、告警和出错选项、优化选项和体系结构相关选项。以下对每一类中最常用的选项进行讲解。
(1)常用选项。
gcc的常用选项如表3.7所示,很多在前面的示例中已经有所涉及。
表3.7 gcc常用选项列表
选项 |
含义 |
-c |
只编译不链接,生成目标文件“.o” |
-S |
只编译不汇编,生成汇编代码 |
-E |
只进行预编译,不做其他处理 |
-g |
在可执行程序中包含标准调试信息 |
-ofile |
将file文件指定为输出文件 |
-v |
打印出编译器内部编译各过程的命令行信息和编译器的版本 |
-Idir |
在头文件的搜索路径列表中添加dir目录 |
前一小节已经讲解了“-c”、“-E”、“-o”、“-S”选项的使用方法,在此主要讲解另外2个非常常用的库依赖选项“-Idir”。
n “-Idir”
正如上表中所述,“-Idir”选项可以在头文件的搜索路径列表中添加dir目录。由于Linux中头文件都默认放到了“/usr/include/”目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过“-Idir”选项来指定,这样,gcc就会到相应的位置查找对应的目录。
比如在“/root/workplace/gcc”下有两个文件:
/*hello1.c*/
#includemy.h>
intmain()
{
printf(Hello!!n);
return0;
}
/*my.h*/
#includestdio.h>
这样,就可在gcc命令行中加入“-I”选项:
[root@localhostgcc]gcchello1.c–I/root/workplace/gcc/-ohello1
这样,gcc就能够执行出正确结果。
小知识 |
在include语句中,“>”表示在标准路径中搜索头文件,““””表示在本目录中搜索。故在上例中,可把hello1.c的“#includemy.h>”改为“#include“my.h””,就不需要加上“-I”选项了。 |
(2)库选项。
gcc库选项如表3.8所示。
表3.8 gcc库选项列表
选项 |
含义 |
-static |
进行静态编译,即链接静态库,禁止使用动态库 |
-shared |
1.可以生成动态库文件 2.进行动态编译,尽可能地链接动态库,只有当没有动态库时才会链接同名的静态库(默认选项,即可省略) |
-Ldir |
在库文件的搜索路径列表中添加dir目录 |
-lname |
链接称为libname.a(静态库)或者libname.so(动态库)的库文件。若两个库都存在,则根据编译方式(-static还是-shared)而进行链接 |
-fPIC(或-fpic) |
生成使用相对地址的位置无关的目标代码(PositionIndependentCode)。然后通常使用gcc的-static选项从该PIC目标文件生成动态库文件 |
我们通常需要将一些常用的公共函数编译并集成到二进制文件(Linux的ELF格式文件),以便其他程序可重复地使用该文件中的函数,此时将这种文件叫做函数库,使用函数库不仅能够节省很多内存和存储器的空间资源,而且更重要的是大大降低开发难度和开销,提高开发效率并增强程序的结构性。实际上,在Linux中的每个程序都会链接到一个或者多个库。比如使用C函数的程序会链接到C运行时库,Qt应用程序会链接到Qt支持的相关图形库等。
函数库有静态库和动态库两种,静态库是一系列的目标文件(.o文件)的归档文件(文件名格式为libname.a),如果在编译某个程序时链接静态库,则链接器将会搜索静态库,从中提取出它所需要的目标文件并直接复制到该程序的可执行二进制文件(ELF格式文件)之中;动态库(文件名格式为libname.so[.主版本号.次版本号.发行号])在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入。
下面举一个简单的例子,讲解如何怎么创建和使用这两种函数库。
首先创建unsgn_pow.c文件,它包含unsgn_pow()函数的定义,具体代码如下所示。
/*unsgn_pow.c:库程序*/
unsignedlonglongunsgn_pow(unsignedintx,unsignedinty)
{
unsignedlonglongres=1;
if(y==0)
{
res=1;
}
elseif(y==1)
{
res=x;
}
else
{
res=x*unsgn_pow(x,y-1);
}
returnres;
}
然后创建pow_test.c文件,它会调用unsgn_pow()函数。
/*pow_test.c*/
#includestdio.h>
#includestdlib.h>
intmain(intargc,char*argv[])
{
unsignedintx,y;
unsignedlonglongres;
if((argc3)||(sscanf(argv[1],%u,x)!=1)
||(sscanf(argv[2],%u,y))!=1)
{
printf(Usage:powbaseexponentn);
exit(1);
}
res=unsgn_pow(x,y);
printf(%u^%u=%un,x,y,res);
exit(0);
}
linux操作系统文章专题:linux操作系统详解(linux不再难懂)linux相关文章:linux教程
c++相关文章:c++教程
评论