国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 課堂 > 電腦知識 > 正文

linux下c程序的鏈接、裝載和庫(2)

2024-05-08 15:56:05
字體:
來源:轉載
供稿:網(wǎng)友

5. 重定義錯誤。

    一個最終的可執(zhí)行文件里,絕對不允許出現(xiàn)兩個同名的全局變量,也不允許出現(xiàn)同名的全局函數(shù)。

    全局函數(shù):只要不用 static 修飾符修飾的函數(shù),全部都是全局的。

    全局變量:函數(shù)外聲明定義,且不加 static 修飾符修飾的變量。

    例如,one.c 里有一個函數(shù) function, 那么你如果想讓 main.c 生成的 main.o 能夠鏈接 one.o 的話,那么 main.c 里就不能再有一個函數(shù)叫做 function 了。否則就會報重定義錯誤。

    這就好像,你的班上有兩個人都叫 小明, 這個情況確實麻煩,你肯定會用各種辦法區(qū)分他們,比如說,大小明,小小明,這種方法,實際上,你已經(jīng)為他們重新命名了。

6. 聲明和定義。

    你也許發(fā)現(xiàn)了一個問題,那就是:main.c 里 有一句

    extern void function();

    這一句不是跟 one.c 里的 function 重名了么。那么編譯器為啥不報錯呢?

    想一想整個過程。

    第一步:

    gcc -c main.c -o main.o

    這一步就是編譯 main.c 的過程,好吧,這一步,編譯器完全不用關心在某個地方還有個 one.c,這個源文件里有一個同名的function。

    仔細解釋一下這句話:

    extern void function();

    你寫程序的時候,要有一種跟編譯器時刻交流的感覺。

    這一句是你寫給編譯器看的,你就是要告訴編譯器這樣一個事實:

    --Hey!編譯器!

    --main.c 這個源文件里要用到一個函數(shù) function,是void 類型的,沒有參數(shù),你暫時不用管這個函數(shù)到底在哪,你先編譯通過,這個函數(shù)最終會被你的哥們鏈接器鏈接過來!

    編譯器:

    --ok!我相信我的哥們鏈接器!

    這個過程就叫做“聲明”。如果沒有這一句,沒有這個過程,編譯器就會在 main.c 里遇見一個陌生的函數(shù)調用 function,嗯,結果就是,敗!

    而這個函數(shù) function 的真正定義就是在 one.c 里。所謂定義,就是具體的實現(xiàn),就是這個函數(shù)大括號里的東西。也可以這么說,沒有大括號(即使沒有 extern 修飾符)的地方就是聲明,有大括號(即使大括號里是空的)的地方,那就是定義。

    還有一句,聲明可以多次,比如說,每一個用到了函數(shù) function 的地方,都要聲明(你可以不用 extern 這個修飾符,試試吧)。但是,定義只有一個,這也符合上一小節(jié)說的:不能重定義!

7. 從硬盤到內存--裝載。

    這一節(jié)不準備總結的太細。

    你寫好的源文件是放在硬盤上的,你編譯成的目標文件也是放在硬盤上的,鏈接成的可執(zhí)行文件也是放在硬盤上的。

    當你,運行這個可執(zhí)行文件的時候,操作系統(tǒng)就會做一件事情:裝載。

    可以簡單粗暴的假想,操作系統(tǒng)把你的可執(zhí)行文件直接復制到內存的某個地方,然后,cpu開始在這個地方去找 main 函數(shù),進而執(zhí)行整個程序。

    所以你的程序才會占內存的空間:變量會占,函數(shù)會占,動態(tài)開辟(例如malloc)的更會占。

8. 節(jié)省一點內存。

    你的同事十分能干,他用他閑暇的時間,積極地擴充他所維護的 one.c,使這個 one.c 更加豐富。比如說,他增加了一個函數(shù)

    int add(int a, int b)

    {

         //省略代碼

    }

    可是,你知道,函數(shù)最終是要占內存空間的。并且,你完全用不到這個新加的函數(shù) add。

    問題就是,你鏈接的時候,已經(jīng)把整個 one.o 鏈接到你的 可執(zhí)行文件里了。這個可執(zhí)行文件確實包含了 add 的具體實現(xiàn)的代碼,也就是說,最終運行的時候,內存里確實會有這一部分,而且是完全沒用的部分。

    你僅僅用到了 one.o 里的一個函數(shù) function 就要鏈接整個 one.o,這就好像,你到飯店,只想吃一個漢堡,卻不得不花錢買一份套餐,浪費。

    你不得不跟你的同事說明一下這個問題,最終你們商量出了一個辦法。

    你的同事決定,將他寫的每一個函數(shù)單獨放到一個源文件里去,比如說,function函數(shù)放到 function.c ,add函數(shù)放到 add.c。

    這樣,一個函數(shù)對應一個源文件,也對應一個目標文件,也就是說,一個目標文件里只有一個函數(shù),沒有其他的東西。

    你使用的時候,就能夠隨便挑選,去鏈接哪個目標文件了。

    比如說,你的同事已經(jīng)有了這些:

    one.c 包含了 void one(){} 函數(shù)

    two.c 包含了 void two(){} 函數(shù)

    three.c 包含了 void three(){} 函數(shù)

    等等……。而且也提供了一份頭文件叫做 all.h, 這個all.h包含了所有他編寫的函數(shù)的聲明。

    你使用的時候先包含這個all.h, 像這樣

    #include "all.h"

    然后,編譯;然后鏈接的時候,你用到了哪個,就在你的gcc命令里加上那個目標文件就行。例如,用到了 void three() 這個函數(shù):

    ld main.o three.o -o go

    這樣就行了。

    但是即便是這樣, 你還是覺得麻煩,你得在心里記錄一下,你用了哪些函數(shù),并且去手動敲下命令進而鏈接,這樣容易出錯。

    任何問題都是有可能解決的,這次也不例外。

    


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 偃师市| 邓州市| 会泽县| 湄潭县| 涞水县| 本溪| 儋州市| 凤冈县| 巫溪县| 博乐市| 新和县| 西乌珠穆沁旗| 上林县| 崇阳县| 河池市| 黄浦区| 临夏市| 简阳市| 二连浩特市| 左云县| 彭州市| 潼南县| 富蕴县| 长乐市| 双江| 南充市| 玉门市| 浠水县| 诸城市| 安康市| 阳春市| 南宫市| 浮山县| 科技| 仙桃市| 册亨县| 大渡口区| 静宁县| 乡城县| 海口市| 开封市|