C陷阱和缺陷 連線

2021-08-27 06:59:55 字數 2033 閱讀 1640

一,概念

聯結器的作用在於把有編譯器或彙編器生成的若干個目標模組,整合成乙個被稱為載入模組可執行檔案的實體,該實體能夠被作業系統直接執行。其中,某些模組式直接作為輸入提供給聯結器的;而另外一些目標木塊則是根據連線過程的需要,從包括有型別printf函式的庫檔案中取得的。

二,連線過程問題的根源

c程式 - > 預處理成demo.i - > 彙編成 demo.s - > 編譯成 demo.o - > 連線成 demo可執行程式

編譯器為程式分配好了記憶體並翻譯成了機器語言,而聯結器了解c語言的記憶體分配和機器語言,所以聯結器可以把各個模組組裝起來。但是,聯結器和編譯器是分開的,即是說聯結器並不清楚c語言的細節什麼的;

編譯器一般一次只處理乙個檔案,不能檢測出多個檔案組合後的問題

外部物件:程式中每個函式和每個外部變數,如果沒有宣告為static,就都是乙個外部物件,分別稱為全域性函式和全域性變數。

通過static修飾的函式和變數,稱為靜態函式和靜態變數。

注:靜態函式和靜態變數在某些c編譯器中也是外部物件,只是它們的名稱會做一些改變,所以不會與其他源程式檔案中的同名函式或同名變數發生命名衝突,可是在其它原始檔中想直接引用該靜態函式或變數時(extern *),也束手無策了。

四,聯結器主要工作是:

當出現同名的外部物件時,處理這類命名衝突。

1)宣告和定義:宣告可以多個(通過extern *),但定義只能由乙個,在乙個檔案中定義,其他檔案中引用。

2)命名衝突與static修飾符:static可以有效地消除命名衝突問題,如果乙個原始檔的某個物件如果不需要共享給其它原始檔,最好用static修飾符把該物件限制為本檔案可見。

3)形參和實參:該部分主要討論的行參和實參的型別匹配問題,主要是預設型別為int型,而一般只允許「大」型別相容「小」型別,而試圖用「小」型別相容「大」型別則會出錯。

4)檢查外部型別:指的是外部宣告的型別要和定義型別一致。譬如指標和陣列很多方面操作上一致的, 但是卻是顯然不同的兩種型別。

5)標頭檔案:解決這些問題的重要方法之一,把外部的宣告寫在標頭檔案中,引用這些外部變數時只需要 include該檔案就行,在統一乙個地方也方便出問題時進行修改。

檢查外部型別舉例:

比如在兩個檔案中的extern int n;和long n;

執行存在著很多可能情況:

1)編譯器檢測到衝突並返回診斷訊息;

2)使用的c語言實現對int和long在內部表示上是一樣的,很巧合地,可以正常工作;

3)二者雖然需要儲存空間大小不同,但它們共享儲存空間恰好可以保證賦給其中之一的值對另乙個有效(比如低端部分共享儲存空間),本來錯誤的程式因某種巧合卻能正常工作,類似第二種情況;

共享儲存空間時給乙個賦值卻相當於對另乙個賦予不同的值,不能正常工作。這樣的引申例子:char filename = "/etc/passwd";和extern char* filename;,雖然前者的引用filename的值將得到指向該陣列起始元素的指標,但filename型別是「字元陣列」,而不是後者的「字元指標」,二者無法以一種合乎情理的方式共存。

/* 改法 1 */

char filename = "/etc/passwd"; /* 檔案1 */

extern char filename; /* 檔案2 */

/* 改法 2 */

char* filename = "/etc/passwd"; /* 檔案1 */

extern char* filename; /* 檔案2 */

五,關於標頭檔案的乙個重要用法

解決外部物件在哪宣告的好方法是使用標頭檔案

標頭檔案一般作為乙個源程式檔案(模組)與外界互動的地方,所以在標頭檔案中一般放置了一些共享用的資源。譬如變數,結構型別等。其實標頭檔案可以作為乙個物件導向程式設計中提到的介面宣告檔案,把所有可能被呼叫的函式提取到頭檔案中,用extern type function(parameters),所有需要呼叫該檔案(模組)中的函式時,只要包含該標頭檔案即可。

c陷阱與缺陷 陷阱

例1 if x y break 這就話的意思就是把y賦值x,判斷x是否為0,實則是在判斷y是否為0 例2 while c c t c n 這句話的意思就是 c t c n 賦值給c,而有 符本身就是不為0的數,所以這就是while 1 的意思。例3 int x 4,p new int p 2 cou...

C陷阱和缺陷學習筆記

詞法陷阱 1 不同於 不要在程式中將兩者寫錯,小心。將表示式與常量比較時,可將常量放在左邊。2 和 不同於 和 3 詞法分析中的貪心法 每個符號應該包含盡可能多的字元。如果 編譯器的 輸入流截至某個字元前都已經分解為乙個個符號,那麼下乙個符號將包括從該字元之後可能組成乙個字元的最長字串。如y x p...

讀《C陷阱和缺陷》(三)

以前一直不知道位運算中的 是什麼情況,今天看了一下位運算,感覺好簡單,前兩者跟運算子 差不多,只不過位運算中操作是按二進位制的方法操作的,比如10和 12他們的二進位制為 1010 和1100 進行 運算,每一位比較出來的結果為 1000 結果是 8。進行 運算,每一位比較的結果是 1110 結果是...