程式環境
我們知道計算機是沒有辦法認識除了二進位制之外的語言,所以我們現在編寫出來的**想要讓計算機認識並實現,就必須把它轉換成二進位制語言.我們把這個過程叫做程式的翻譯過程.
程式的翻譯過程又分為四個階段:
預處理: 在這個階段,它只做了四個工作:巨集替換,去注釋,標頭檔案展開和條件編譯.
編譯: 將c語言編譯成為組合語言.
彙編:將組合語言變為目標二進位制檔案
鏈結:將目標二進位制檔案和庫函式鏈結形成可執行檔案
程式執行的過程:
程式必須載入到記憶體中
函式的執行開始,接著就呼叫main()函式
開始執行程式**,這時函式需要使用乙個執行時堆疊,儲存函式的區域性變數和返回位址.程式同時也可以使用靜態記憶體,儲存在靜態記憶體中的變數在程式執行的整個過程中就一直保留著他們的值.
終止程式,可能正常終止main()函式,也可能異常終止.
預處理詳解:
預定義符號:
__file__ //進行編譯的原始檔
__line__ //檔案當前的行號
__date__ //檔案被編譯的日期
__time__ //檔案被編譯的時間
__stdc__ //如果編譯器遵循ansi c,其值為1,否則未定義
例如: printf("file:%s line:%d\n",__file__,__line__);
#define
語法: #define name stuff
例如: #define max 100
#define reg register //用register這個關鍵字,建立乙個簡短的名字
#define do_forever for(;;) //用更形象的符號來替換一種實現
#define case break;case //在寫case語句的時候自動把break寫上
//如果定義的stuff過長,可以分為幾行寫,除了最後一行外,每行的後面都加乙個反斜槓(續行符)
#define debug_print printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n", \
__file__,__line__, \
__date__,__time__)
#define機制包括了乙個規定,允許把引數替換到文字中,這種實現通常稱為巨集或定義巨集.
語法:define name(parament-list) stuff
例如: #define square(x) x*x
#define square(x) (x)*(x)
#define替換在程式中擴充套件#define定義符號和巨集時,需要涉及幾個步驟:
在呼叫巨集時,首先對引數進行檢查,看看是否包含由#define定義的符號,如果是,則它們首先被替換.
替換文字隨後被插入到程式中原本文字的位置.對於巨集,引數名被他們的值替換.
最後,再次對結果檔案進行掃瞄,看看它是否包含任何由#define定義的符號.如果是,就重複上面操作.
巨集的劣勢:
每次使用巨集的時候,乙份巨集定義的**將插入到程式中.除非巨集比較短,否則可能大幅度增加程式的難度.
巨集時沒有辦法除錯的
巨集由於型別無關,也就不夠嚴謹
巨集可能會帶來運算子優先順序的問題,導致程式容易出錯
注意:
巨集引數和#define定義中可以出現其它#define定義的變數,但是對於巨集,不能出現遞迴.
當預處理搜尋#define定義的符號的時候,字串常量的內容並不被搜尋.
巨集和函式的對比:屬性
#define定義巨集
函式**長度
每次使用時,巨集**都會被插入到程式中.除了非常小的巨集之外,程式的長度會大幅度增長
函式**只出現於乙個地方;每次使用這個函式時,都呼叫那個地方的乙份**
執行速度
更快存在函式的呼叫和返回的額外開銷,所以相對慢一點
操作符優先順序
巨集引數的求值是在所有周圍表示式的上下文環境裡,除非加上括號,否則臨近操作符的優先順序可能會產生不可預料的後果,所以建議巨集在書寫的時候多些括號.
函式引數只在函式呼叫的時候求值一次,它的結構值傳遞給函式.表示式的求值結構更容易**.
帶有***的引數
引數可能被替換到巨集體中的多個位置,所以帶有***的引數求值可能會產生不可預料的結構.
函式引數只在傳值的時候求值一次,結果更容易控制.
引數型別
巨集的引數與型別無關,只要對引數的操作是合法的,它就可以使用於任何引數型別.
函式的引數是與型別有關的,如果引數的型別不同就需要不同的函式,即使他們執行的任務是不同的.
除錯巨集是不方便除錯的
函式時可以逐語句除錯的
遞迴巨集是不能遞迴的
函式是可以遞迴的
命名約定:一般來講函式的巨集的使用語法很相似,所以語言本身沒法幫我們區分二者.所以我們一般:把巨集名全部大寫,函式名不要全部大寫.
#undef(用於移除乙個巨集定義)
#undef name //如果現存的乙個名字需要被重新定義,那麼它的舊名字首先要被移除.
程式環境與預處理
c語言的程式環境主要分為翻譯環境和執行環境。其中翻譯環境是將源 轉換為可執行的機器指令。2.翻譯環境又分為編譯和鏈結兩個部分。1.1編譯又分為三個小部分 預編譯 預處理 a.包含標頭檔案b.注釋刪除。c.define定義的常量的替換。d.define定義的巨集的替換。在gcc linuxs環境下的c...
程式環境和預處理
程式環境 1.翻譯環境 編譯 鏈結 先將組成乙個程式的每個原始檔通過編譯轉換成目標檔案,再將每個目標檔案通過編譯器 在一起鏈結成乙個 可執行檔案 翻譯過程 1.預處理 c c 標頭檔案展開,巨集替換,去注釋,條件編譯 2.編譯 c 彙編 3.彙編 彙編 二進位制 4.鏈結 常見的鏈結方式 2.執行環...
程式環境和預處理
一 程式的編譯環境和執行環境 1 每乙個程式的原始檔都會通過編譯過程轉換為相應的目標 2 每乙個目標 由鏈結器 在一起,形成乙個單一的可執行程式。3 鏈結器同時也會引入標準庫函式中被程式任意引用的庫函式,而且還可以搜尋程式設計師的個人程式庫,將需要的函式也鏈結到程式之中。編譯分為幾個階段組成 程式執...