四时宝库

程序员的知识宝库

软件特攻队|编译链接,C++中一个容易忽略却有趣的问题

在C++中,存在着一个有趣却容易被忽略的编译链接问题,那就是为什么在使用pow函数不需要链接libm库?

在思考这个问题前,我们先回顾下,什么情况下需要制定链接库?

#include<stdio.h>

#include<math.h>

int main(void)

{

int b = 2;

double a = pow(b,b);

printf("%f\n",a);

return 0;

}

一段很简单的代码:使用pow(x,y)用于计算x的y次幂。

我们注意到由于pow函数不在lib库中,而默认情况下,编译时候只会链接libc库,因此如果不指定链接库的话,则会报错:

$ gcc -o test test.c

/tmp/ccKDgtzz.o: In function `main':

test.c:(.text+0x22): undefined reference to `pow'

collect2: error: ld returned 1 exit status

错误信息指出,找不到pow函数的定义。

通过查询手册我们能够看到,编译是需要包含头文件main.h和链接数学库。

$ man pow

#include <math.h>


double pow(double x, double y);

float powf(float x, float y);

long double powl(long double x, long double y);


Link with -lm.

即像下面这样是可以的:

$ gcc -o test test.c -lm

$ ./test

4.000000

gcc在编译的时候默认链接的是libc库,其他库需要手动指定。

但是,看下面的代码:

#include<iostream>

#include<cmath>

int main()

{

int b = 2;

double a = pow(b,b);

std::cout<<a<<std::endl;

return 0;

}

编译运行:

$ g++ -o test test.cpp

$ ./test

4

我们并没有手动指定链接库,但是却可以编译过!

问题

回过头来在看,为什么pow函数在C++中使用不需要手动指定链接数学库而C里面却需要?

解答这个问题,我们首先需要了解C++程序中,有没有链接libm库?

我们查看C++的ldd库:

$ ldd test

linux-vdso.so.1 => (0x00007ffd41bda000)

libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6230cca000)

libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f62309c1000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f62305f7000)

/lib64/ld-linux-x86-64.so.2 (0x00007f623104c000)

libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f62303e1000)

从中可知,程序除了链接最基本的libstdc++库,还链接了libc和libm库!也就是说,虽然在C++中没有手动指定链接,但是实际上已经链接了。那么什么时候链接上的呢?

我们再看libstdc++的链接库发现:

$ ldd /usr/lib32/libstdc++.so.6

linux-gate.so.1 => (0xf7f92000)

libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xf7da6000)

libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7bf0000)

/lib/ld-linux.so.2 (0xf7f94000)

libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf7bd3000)

看见没有!原来是libstdc++已经链接了libm库,这也就解释了为什么C++代码中不需要手动指定链接数学库libm。

欢迎关注软件特攻队!

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接