一個(gè)有趣卻容易忽略的編譯鏈接問(wèn)題
什么情況需要指定鏈接庫(kù)?
在解釋之前,先回顧一下。//來(lái)源:公眾號(hào)【編程珠璣】
//https://www.yanbinghu.com
#include
#include
int?main(void)
{
????int?b?=?2;
????double?a?=?pow(b,b);
????printf("%f\n",a);
????return?0;
}
代碼本身比較簡(jiǎn)單,pow(x,y)用于計(jì)算x的y次冪。這里由于pow函數(shù)并不在lib庫(kù)中,默認(rèn)情況下,編譯的時(shí)候只鏈接了libc庫(kù),因此如果不指定鏈接庫(kù),則會(huì)報(bào)錯(cuò):$?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
從報(bào)錯(cuò)信息來(lái)看,我們知道是找不到pow函數(shù)的定義。通過(guò)man手冊(cè)也可以查看到,編譯是需要包含頭文件math.h和鏈接數(shù)學(xué)庫(kù)的:$?man?pow
???????#include?
???????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在編譯的時(shí)候默認(rèn)鏈接的是libc庫(kù),其他庫(kù)需要手動(dòng)指定。但是,看下面的代碼://來(lái)源:公眾號(hào)【編程珠璣】
//作者:守望先生
#include
#include
int?main()
{
????int?b?=?2;
????double?a?=?pow(b,b);
????std::cout::endl;
????return?0;
}
編譯運(yùn)行:$?g ?-o?test?test.cpp
$?./test
4
我們并沒(méi)有手動(dòng)指定鏈接庫(kù),但是卻可以編譯過(guò)!
那么,問(wèn)題來(lái)了!
為何在C 中使用pow函數(shù)不需要手動(dòng)指定鏈接數(shù)學(xué)庫(kù)libm,而C里面卻需要呢?為了解答這個(gè)問(wèn)題,我們必須知道C 的程序中,到底有沒(méi)有鏈接libm庫(kù)。如何查看呢?還記得在《linux常用命令-開(kāi)發(fā)調(diào)試篇》中提到的ldd嗎?它可以查看當(dāng)前程序鏈接了哪些動(dòng)態(tài)庫(kù):$?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)
看到?jīng)]有,除了鏈接了最基本的libstdc 庫(kù),還鏈接了libc和libm庫(kù)!也就是說(shuō),雖然沒(méi)有手動(dòng)指定鏈接,但是實(shí)際上還是鏈接了。但是這是什么時(shí)候鏈接上的呢?我們?cè)倏磍ibstdc 的鏈接庫(kù)發(fā)現(xiàn):$?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)
看見(jiàn)沒(méi)有!原來(lái)是libstdc 已經(jīng)鏈接了libm庫(kù),這也就解釋了為什么C 代碼中不需要手動(dòng)指定鏈接數(shù)學(xué)庫(kù)libm。總結(jié):
通過(guò)前面的內(nèi)容我們總結(jié)如下:- C代碼編譯時(shí),通常會(huì)默認(rèn)鏈接libc庫(kù)
- C 代碼編譯時(shí),通常會(huì)默認(rèn)鏈接libstdc 庫(kù)
- 由于libstdc 中有依賴一些數(shù)學(xué)函數(shù)或者libc庫(kù)中的函數(shù),因此默認(rèn)鏈接了libc庫(kù)和libm庫(kù)。
作者:守望先生來(lái)源:編程珠璣版權(quán)歸原作者所有,如有侵權(quán),請(qǐng)聯(lián)系刪除。