Linux 中常用链接来解决一些库函数的问题。在编译时链接可以生成可执行文件。了解一些链接的基本过程,能让我们在开发中减去不少的麻烦!
编译时使用 gcc -lm
程序功能很简单,下面的示例展示了exp()函数的用法。
(代码一)
#include <stdio.h>
#include <math.h> //exp
int main(int argc, char const *argv[]){
//double x = 0;
printf("The exponential value of %lf is %lf\n", 0, exp(0));
printf("The exponential value of %lf is %lf\n", 0+1, exp(0+1));
printf("The exponential value of %lf is %lf\n", 0+2, exp(0+2));
return(0);
}
编译结果:
我们再来看下面这种情况:
(代码二)
#include <stdio.h>
#include <math.h>
//#define X 0
int main(int argc, char const *argv[]){
double x = 0;
printf("The exponential value of %lf is %lf\n", x, exp(x));
printf("The exponential value of %lf is %lf\n", x+1, exp(x+1));
printf("The exponential value of %lf is %lf\n", x+2, exp(x+2));
return(0);
}
编译输出:
同样的编译方法却编译不过了,提示对‘exp’未定义的引用。
来看看man手册exp函数的使用:
发现exp函数除了需要包含头文件math.h外,编译时还需要使用-lm链接。
编译时在包含链接-lm,看看是否编译通过:
库链接一般放在命令行结尾。
问题
两段代码同样都调用了exp函数,为什么一个需要链接,一个不需要链接呢?
我们可以观察到,代码一调用exp传入的参数是常量为 0 。代码二调用exp传入的参数是变量 x,那么对于代码一会不会在运行之前就计算好了呢?
来看看它们的汇编代码:
(代码一)
第一段代码没有看到调用exp的身影。实际上,通过汇编代码可以看到,当传入参数为常量时,就已经计算好了值,最后根本不需要调用exp函数。
(代码二)
汇编的具体细节我们无需尽知,变量型的参数,其值在运行时确定,因此需要调用,第二段代码call exp指令调用了exp函数。
ldd命令查看链接库
代码一:
在Linux平台上最广泛使用的C函数库是glibc,其中包括C标准库的实现。几乎所有C程序都要调用glibc的库函数,所以glibc是Linux平台C程序运行的基础。glibc提供一组头文件和一组库文件,最基本、最常用的C标准库函数和系统函数在libc.so库文件中,几乎所有C程序的运行都依赖于libc.so (例如 printf)
代码二:
使用math.h中声明的库函数还有一点特殊之处,gcc命令行必须加-lm选项,因为数学函数位于libm.so库文件中(这些库文件通常位于/lib目录下),-lm选项告诉编译器,我们程序中用到的数学函数要到这个库文件里找。
总结
调用函数是否需要链接,可以使用命令“man 3 函数名“查看,如果需要链接库,最后都有说明。调用包含于libc库中的函数不需要链接。
(微信公众号: 程序猿编码 )
(添加本人微信,备注加群,进入程序猿编码交流群,领取学习资料,获取每日干货)
欢迎关注微信公众号“程序猿编码”,这里Linux c/c++ 、Go语言、数据结构与算法、网络编程相关知识,常用的程序员工具。还有汇聚精炼每日时政、民生、文化、娱乐新闻简报,即刻知晓天下事!