中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
mingw64下動(dòng)態(tài)庫和靜態(tài)庫鏈接的真正區(qū)別和用法(詳細(xì))_mingw 編譯動(dòng)態(tài)庫

筆者一直以來都對(duì)mingw64下動(dòng)態(tài)庫和靜態(tài)庫鏈接的真正區(qū)別和用法存疑,于是做了一些測(cè)試,這篇文章記錄了測(cè)試過程和測(cè)試結(jié)果,如果只想知道結(jié)果可以跳轉(zhuǎn)到文章末尾

一、準(zhǔn)備工作

首先準(zhǔn)備三個(gè)測(cè)試文件


其中add.c最終會(huì)被編譯會(huì)靜態(tài)庫或動(dòng)態(tài)庫,被測(cè)試文件main.c調(diào)用
使用如下命令構(gòu)建靜態(tài)庫

gcc -c add.c -o add.o
ar rcs libadd.a add.o

得到靜態(tài)庫如下:


接著使用如下命令構(gòu)建動(dòng)態(tài)庫

gcc -fPIC -shared add.c -o libadd.dll

得到動(dòng)態(tài)庫如下:

二、測(cè)試過程

1.當(dāng)一個(gè)靜態(tài)庫和一個(gè)動(dòng)態(tài)庫重名,并且位于同一文件夾下,編譯器優(yōu)先鏈接哪一個(gè)

首先把五個(gè)文件放在同一路徑下


已知在編譯指令中,鏈接libadd.a 和鏈接libadd.dll都只需要加上以下參數(shù)

-ladd

也即這里靜態(tài)庫和動(dòng)態(tài)庫可以看做是重名的,于是我們先來測(cè)試當(dāng)輸入-ladd的時(shí)候,gcc會(huì)默認(rèn)鏈接哪個(gè)庫
輸入指令:

gcc main.c -I ./ -L ./ -ladd -o normal_two_implicit

得到文件


文件名是為了對(duì)比實(shí)驗(yàn)方便而設(shè)置的,其中normal意味著正常狀態(tài),與后面要進(jìn)行的反常測(cè)試相對(duì)應(yīng),two表示靜態(tài)庫和動(dòng)態(tài)庫同時(shí)位于同一文件夾下,與之后將某個(gè)庫移走單獨(dú)測(cè)試剩下的庫相對(duì)應(yīng),implicit意為在鏈接命令中隱式指出庫名稱(即-l格式的指明方法),與之后顯示給出庫的全稱的測(cè)試對(duì)應(yīng)。
雖然現(xiàn)在得到了可執(zhí)行文件,但是現(xiàn)在我們還無法判斷默認(rèn)鏈接的是哪一個(gè)庫,于是繼續(xù)進(jìn)行測(cè)試
先把libadd.dll暫時(shí)移到其他文件夾里,只保留libadd.a,再鍵入同樣的命令:

gcc main.c -I ./ -L ./ -ladd -o normal_a_implicit

得到文件


這里的exe一定鏈接的是靜態(tài)庫,而且和上一個(gè)exe大小完全相同,因此合理推測(cè)前一個(gè)exe也是鏈接了靜態(tài)庫,也即:當(dāng)兩種同名庫同時(shí)存在于同一文件夾,并且使用-l格式參數(shù)隱式指出鏈接庫名稱時(shí),gcc優(yōu)先鏈接后綴為.a的庫(為什么不說優(yōu)先鏈接靜態(tài)庫?后續(xù)的測(cè)試會(huì)說明)
然后把libadd.a暫時(shí)移到其他文件夾里,只保留libadd.dll,再鍵入同樣的命令:

gcc main.c -I ./ -L ./ -ladd -o normal_dll_implicit

得到文件


文件大小只有54KB,小于前兩個(gè),因此這是個(gè)鏈接了動(dòng)態(tài)庫的exe

因此得到結(jié)論:當(dāng)一個(gè)靜態(tài)庫和一個(gè)動(dòng)態(tài)庫重名,并且位于同一文件夾下,編譯器優(yōu)先鏈接后綴.a的庫

2.-static參數(shù)有什么用

之前一直以為,加了-static就是靜態(tài)鏈接,做出來的exe一定就是那種完全可以移植的,但是經(jīng)過測(cè)試以后我發(fā)現(xiàn)我大錯(cuò)特錯(cuò)
首先把libadd.a和libadd.dll放回原位


然后輸入以下命令:

gcc -static main.c -I ./ -L ./ -ladd -o normal_two_implicit_static

得到:


文件大小為64KB,這說明不出所料地,編譯器優(yōu)先鏈接了靜態(tài)庫,這和-static關(guān)鍵字很搭,接下來把libadd.dll暫時(shí)移走,只留下libadd.a,輸入以下命令

gcc -static main.c -I ./ -L ./ -ladd -o normal_a_implicit_static

得到


64KB,鏈接了靜態(tài)庫,依然在意料之中
這次移走libadd.a,只留下libadd.dll,然后輸入以下命令

gcc -static main.c -I ./ -L ./ -ladd -o normal_dll_implicit_static

錯(cuò)誤出現(xiàn)了:


錯(cuò)誤信息為并沒有找到庫文件!這和我們的預(yù)設(shè)也一致,因?yàn)?static禁用了動(dòng)態(tài)庫,所以不再能找得到動(dòng)態(tài)庫dll
測(cè)試至此本可以結(jié)束,但是這里仍然存在一個(gè)疑問:我們到目前為止還沒有通過顯式的指出文件名來鏈接庫,因?yàn)槠浣Y(jié)果似乎不用想都可以知道,那就是給出什么文件名就鏈接哪個(gè)文件,不可能出現(xiàn)重名的情況,這當(dāng)然是對(duì)的,但是在-static關(guān)鍵字的加持下,似乎在另一個(gè)角度出現(xiàn)了有意思的現(xiàn)象
再一次把文件歸位在一起

鍵入如下命令:

gcc -static main.c -I ./ -L ./ libadd.a -o normal_a_explicit_static

得到文件


沒有問題
然后鍵入如下命令

gcc -static main.c -I ./ -L ./ libadd.dll -o normal_dll_explicit_static

根據(jù)之前的經(jīng)驗(yàn),我猜測(cè):由于-static禁用了動(dòng)態(tài)庫鏈接的選項(xiàng),那么這條命令應(yīng)該也會(huì)失敗并報(bào)錯(cuò),但是奇怪的事情發(fā)生了,命令正常運(yùn)行并且得到了正常的動(dòng)態(tài)庫鏈接exe(因?yàn)樗拇笮?4KB)


至此我們得到了第二個(gè)十分有用的結(jié)論:-static并不禁用動(dòng)態(tài)鏈接,它只是禁用了采用隱式指明庫名法(即以-l格式指明庫名)時(shí)動(dòng)態(tài)鏈接的選項(xiàng),如果你愿意的話完全可以在有-static的情況下輸入完整的動(dòng)態(tài)庫dll的全稱來進(jìn)行動(dòng)態(tài)鏈接

3.編譯器靠什么識(shí)別一個(gè)庫時(shí)靜態(tài)庫還是動(dòng)態(tài)庫(后綴還是二進(jìn)制內(nèi)容)

這個(gè)疑問乍看起來有些多次一舉:后綴為.a的就是靜態(tài)庫,后綴為.dll的就是動(dòng)態(tài)庫呀。
但是事實(shí)真的如此嗎?我們完全可以通過修改后綴名而保持它們的二進(jìn)制數(shù)據(jù)并不變化,修改以后真正的靜態(tài)庫后綴為.dll,而真正的動(dòng)態(tài)庫后綴為.a,。在這種情況下如果將.a鏈接進(jìn)去,編譯器會(huì)辨別出它實(shí)際上是個(gè)披著靜態(tài)庫外皮的動(dòng)態(tài)庫呢,還是會(huì)傻傻地將其當(dāng)做靜態(tài)庫打包進(jìn)exe?于是有了下面的測(cè)試:
修改后綴名的過程略去


經(jīng)過修改后綴名,現(xiàn)在這里的.a才是真正的動(dòng)態(tài)庫,而.dll才是真正的靜態(tài)庫
鍵入以下命令:

gcc main.c -I ./ -L ./ -ladd -o unnormal_two_implicit

得到文件


文件只有54KB,這說明它實(shí)際上鏈接了動(dòng)態(tài)庫,也即現(xiàn)在的.a庫,這與我們測(cè)試1中的結(jié)論也相同,即:當(dāng)同名庫同時(shí)存在時(shí),隱式指明庫名會(huì)默認(rèn)優(yōu)先鏈接.a庫(這也是為什么前面不說優(yōu)先鏈接靜態(tài)庫的原因,因?yàn)?a不一定是靜態(tài)庫,在本例中它是一個(gè)披著靜態(tài)庫后綴的動(dòng)態(tài)庫)
于是得到有用的第三條結(jié)論:編譯器靠二進(jìn)制內(nèi)容識(shí)別靜態(tài)庫和動(dòng)態(tài)庫,而不會(huì)被其后綴名所迷惑

三、結(jié)論

1.當(dāng)一個(gè)靜態(tài)庫和一個(gè)動(dòng)態(tài)庫重名,并且位于同一文件夾下,編譯器優(yōu)先鏈接后綴.a的庫
2.-static并不禁用動(dòng)態(tài)鏈接,它只是禁用了采用隱式指明庫名法(即以-l格式指明庫名)時(shí)動(dòng)態(tài)鏈接的選項(xiàng),如果你愿意的話完全可以在有-static的情況下輸入完整的動(dòng)態(tài)庫dll的全稱來進(jìn)行動(dòng)態(tài)鏈接
3.編譯器靠二進(jìn)制內(nèi)容識(shí)別靜態(tài)庫和動(dòng)態(tài)庫,而不會(huì)被其后綴名所迷惑

下面以編程人員的角度,根據(jù)以上三條結(jié)論再導(dǎo)出出幾條實(shí)用結(jié)論:

Q:當(dāng)需要把一個(gè)dll鏈接進(jìn)程序的時(shí)候該怎么做?
A:在不確定是否有重名庫的情況下,建議直接在編譯參數(shù)中顯式給出庫名的全稱,如果確定沒有重名靜態(tài)庫的話,可以考慮使用-l的參數(shù)指出dll的名稱

Q:當(dāng)需要進(jìn)行靜態(tài)編譯,即把所有庫打包放進(jìn)exe以保證其良好的不受環(huán)境依賴性的時(shí)候該怎么做?
A:只加一條-static并不會(huì)完事大吉,建議仔細(xì)檢查給出的庫中不包含動(dòng)態(tài)庫,然后加上-static參數(shù)作為最終檢查

Q:我要開發(fā)一個(gè)程序,程序運(yùn)行時(shí)需要調(diào)用一些第三方動(dòng)態(tài)庫如opencvworld455.dll,但是我又希望我編譯出的exe可以單獨(dú)發(fā)布出去讓其他人運(yùn)行,可以做到把opencvworld455.dll靜態(tài)鏈接到exe中嗎?
A:不能這么做,動(dòng)態(tài)庫無法靜態(tài)鏈接,這是庫的二進(jìn)制內(nèi)容差異決定的,要發(fā)布依賴第三方dll的可執(zhí)行文件exe,必須同時(shí)打包發(fā)布其依賴的第三方dll(有些商業(yè)軟件為了保證在一些連基本dll環(huán)境如msvcr.dll都沒有的機(jī)器上運(yùn)行,甚至?xí)⑷縟ll和exe一起打包發(fā)布)

四、注

1.本文省略了一些與主題相關(guān)性不高的測(cè)試過程,比如測(cè)試第一個(gè)問題,重名問題時(shí),并沒有給出顯式指明庫名的結(jié)果,以及第三個(gè)問題,編譯器靠什么識(shí)別一個(gè)庫時(shí)靜態(tài)庫還是動(dòng)態(tài)庫問題中,也沒有給出加上-static之后的測(cè)試結(jié)果,另外僅憑文件大小就判斷鏈接了靜態(tài)庫和動(dòng)態(tài)庫未免有些草率,這些問題都從某種程度上顯得測(cè)試的邏輯性不夠嚴(yán)密。但實(shí)際上筆者幾乎做了一切可以想到的測(cè)試,并且通過移走dll再運(yùn)行exe發(fā)現(xiàn)不能運(yùn)行才判斷其為動(dòng)態(tài)鏈接產(chǎn)物,發(fā)現(xiàn)能運(yùn)行才判斷其為靜態(tài)鏈接產(chǎn)物,這些測(cè)試結(jié)果由于結(jié)果顯而易見和篇幅限制(懶)的緣故在文章中沒有給出,感興趣的讀者可以自己試試
2.本文測(cè)試的平臺(tái)為mingw64+windows10,結(jié)論并不一定適用于其他平臺(tái)
3.如有錯(cuò)誤,歡迎指正

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
gcc編譯過程介紹
C++靜態(tài)庫與動(dòng)態(tài)庫
淺談GCC/Clang生成和鏈接靜態(tài)庫/動(dòng)態(tài)庫 | 程序員修煉之道
C 程序編譯之謎(二)——隱藏源碼,動(dòng)態(tài)和靜態(tài)鏈接庫的秘密
C 調(diào)用靜態(tài)庫和動(dòng)態(tài)庫
GCC編譯器(2)
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服