天天看點

C-程式的編譯連結、宏、條件編譯、頭檔案展開

文章目錄

    • 一、編譯連結
    • 二、宏
    • 三、條件編譯
    • 四、頭檔案展開

一、編譯連結

1.程式的環境、翻譯

  1. 組成一個程式的每個源檔案通過編譯轉換成目标代碼
  2. 每個目标檔案由連結器捆綁在一起,形成一個單一而完整的可執行程式
  3. 連結器同時也會引入标準C函數庫中被該程式調用的函數,也可以搜尋程式員個人的程式庫,将其需要的函數也連結到程式中

2.程式執行過程

  1. 程式必須載入記憶體。有作業系統時,一般這個由作業系統完成;獨立環境下,程式的載入必須由手工安排,也可能是通過可執行代碼置入隻讀記憶體來完成的
  2. 程式執行便開始。接着調用main函數
  3. 開始執行程式代碼。程式将使用一個運作時堆棧,存儲函數的局部變量和傳回位址。程式同時也可以使用靜态記憶體,存儲于靜态記憶體中的變量在程式的整個執行過程一直保留它們的值
  4. 終止程式。正常終止main函數,或者是意外終止

3.程式編譯連結過程

  1. 預處理:頭檔案展開、宏替換、條件編譯、去掉注釋
  2. 編譯:文法檢查、生成彙編代碼
  3. 彙編:将彙編代碼轉換成二進制碼
  4. 連結:生成可執行程式
    C-程式的編譯連結、宏、條件編譯、頭檔案展開

二、宏

允許把參數替換到文本中,這種實作通常稱為宏或定義宏。

1.#define 定義辨別符

例如:#define name stuff

如果是多行替換的話,必須每行後面加上續行符 ’ \ ’ ,因為宏隻會替換後面的一行而已。

例如:

#define DEBUG_PRINT printf("file:%s\tline:%d\t  \
                           date:%s\ttime:%s\n" ,\
                           __FILE__,__LINE__ ,  \
	                       __DATE__,__TIME__ )
           

注意:在定義宏時,應盡可能地多使用括号,避免臨近操作符之間的互相作用。

2.宏替換

  1. 在調用宏時,首先對參數進行檢查,看看是否包含任何由#define定義的符号。如果是,它們首先被替換。
  2. 替換文本随後被插入到程式中原來文本的位置。對于宏,參數名被它們的值替換。
  3. 最後,再次對結果檔案進行掃描,重複1号過程。

注意:宏參數和#define定義中可以出現其他#define定義的變量,宏不能出現遞歸。當處理器搜尋#define定義的符号時,字元串常量不被搜尋。

3.#和##

#:把一個宏參數變成對應的字元串。

例如:

C-程式的編譯連結、宏、條件編譯、頭檔案展開

##:可以把位于它兩邊的符号合成一個符号。它允許宏定義從分離的文本片段建立辨別符。

例如:

#define ADD_TO_SUM(num,value)\
sum##num+=value;
ADD_TO_SUM(3, 7);// 給sum3增加7
           

4.宏和函數

宏的優勢:

  • 宏比函數在程式的規模和速度方面更勝一籌。
  • 宏與類型無關。

宏的劣勢:

  • 長的宏會增加代碼篇幅。
  • 宏沒法調試。
  • 宏與類型無關,不夠嚴謹。
  • 宏會有優先級問題。

三、條件編譯

常用:

  1. #if #endif
  2. #if #elif #else #endif

條件編譯可以跨平台。

四、頭檔案展開

  1. #include指令使另外一個檔案被編譯:預處理器先删除這條指令,并用包含檔案的内容替換。這樣一個檔案被包含10次,那就實際被編譯10次。
  2. 庫檔案一般用 < > 包含;本地檔案一般用 “ ” 包含。
  3. 檔案開頭寫:#pragma once 可以避免頭檔案的重複引入。

繼續閱讀