預處理的那點事兒

2021-07-23 13:13:49 字數 3221 閱讀 2167

編譯乙個c程式的第乙個步驟就是對它進行預處理,在平常學習的時候,很多人認為預處理就是include和define兩種。其實在預處理裡,這兩個只能算是常用的,下面將把ansi標準定義的c語言預處理指令為大家羅列出來。

除了上面所說的外,還有以下的巨集:

_ line_:表示正在編譯的檔案的行號;

_ file_:表示正在編譯的檔案的名字;

_ date_:表示編譯時刻的日期字串;

_ time_:表示編譯時刻的時間字串;

_ stdc_:判斷該檔案是不是定義標準c程式;

1.巨集定義

<1>數值巨集定義

在平時寫**的時候,我們經常會定義一些數值,例如pi的值為3.14,但在後續應用中可能需要提高精度,此時需要將所有在**中出現的pi都改掉,這樣的工作量非常大。一般來說,我們會在**的最前端寫上:#define pi 3.14 這樣子在需要用3.14的時候都寫得是pi,需要改動的時候只需要改動這個巨集定義。

注意:編譯器在編譯的時候,會將**中所有的pi都換成我們定義的具體數值。

<2>表示式巨集定義

當然,除了可以巨集可以定義數值,表示式這種也是可以的。

例如:表示一年有多少秒 #define sum 60* 60* 24* 365

那麼如果定義的是乙個巨集函式呢?

比如求乙個數x的平方。就可以寫成:#define sum(x) x*x

當x=10 ,編譯的時候就是10 * 10。可當表示式比較複雜,我們寫出的可能是(10+x) *(10+x),我們想表達的是(10+x)這個數的平方,可編譯器執行時,它會這樣理解:10+x *10+x ,這個就和我們期望的有點差距了,所以當我們要用巨集去定義函式表示式之類的時候,一定要注意表示式的優先順序!

<3>.#undef

#undef是用來取消巨集定義的,用法如下:

#define pi 3.1415925

…… #undef

在#undef後的pi,值就不在是3.1415925了。

2.條件編譯

在預處理裡很重要的一類就是條件編譯,條件編譯的意思就是說在某種情況下,我們需要執行第一段程式,當在另一種情況下時,需要執行另一段。最常見的應該是我們用的一些軟體包,當操作位數是32位時,是怎樣,換成64位又怎樣。下面就說條件編譯的三種形式:

<1>

#ifdef 識別符號

…a…

#else

…b…

#endif

如果識別符號已被#define定義,則對a進行編譯,否則對b進行編譯。如果沒有else,可直接省略這段。變成:

#ifdef 識別符號

…a…

#endif

<2>

#ifndef 識別符號

…a…

#else

…b…

#endif

如果識別符號沒有被#define定義,則對a進行編譯,否則對b進行編譯。

<3>

#if 常量表示式

…a…

#else

…b…

#endif

如果常量表示式為真,則對a進行編譯,否則對b進行編譯。所以這種形式可以讓程式在不同的條件下完成不同的功能。

3.檔案包含

檔案包含是預處理的乙個重要功能,它可以把多個原始檔進行編譯,生成乙個目標檔案。每次在我們寫**的時候,首先會引用標頭檔案,這就是乙個最常見的檔案包含。

#include《檔名》和#include」檔名」到底有什麼差異?

用尖括號括起來的表示預處理需要帶系統規定的路徑下去獲得這個檔案。

雙引號表示預處理先去當前路徑下去查詢這個檔案,如果查詢不到再去查詢系統指定的路徑資訊。

4.#pragma

關於pragma的用法我們用的最多的是:#pragma once

#pragma once

只要在標頭檔案中最開始接入這條指令就可以避免標頭檔案被多次編譯。

5.函式與巨集的不同之處

之前在前面說了如何定義乙個巨集函式,很多人就巨集和函式傻傻分不清楚了。接下來,用乙個**展現一下:屬性巨集

函式**長度

每次使用時,巨集**將被替換到程式中。除了非常小的巨集之外,其他的長度都會大幅度增長。

**只出現在乙個地方,每次呼叫函式時,只是跳到這個部分在執行一遍。

執行速度

更快存在壓棧的額外開銷

引數求值

引數每次用於巨集定義都需要重新求值,具有***的巨集引數可能會導致不可預料的結果。

引數被呼叫時會求值一次,在函式中使用引數不會造成其他特殊問題。

引數型別

巨集和型別無關,只要對引數的操作是合法的,可用於各種型別

和型別有關,型別不同就需要使用不同的函式。

6.預處理

當乙個程式寫好後,第一步是進行預處理。預處理的目的是:巨集定義的具體化;去掉注釋;展開標頭檔案;條件編譯。預處理完成生成的是「.i」檔案,當這一步進行完後,開始進行編譯。編譯主要是將c語言轉換成組合語言,當這個工作完成後,生成「.s」檔案。接下裡進行的是彙編階段,這個階段的主要工作是將組合語言變成二進位制,生成「.o」檔案。最後進入鏈結階段,完成「合併段表」和「符號表的合併及符號的重定義」。每個階段都有自己的任務,共同配合完成整個預處理的過程。

C 的那點事兒

一 預處理 定義 在編譯之前所做的處理,主要包括 標頭檔案 預處理會展開 巨集定義 預處理會替換掉 條件編譯 二 標頭檔案 作用 將一些公用 如函式原型宣告,型別宣告,全域性變數宣告,巨集定義等,放到乙個檔案中,以提供跨工程 復用,減少 重複書寫。處理方式 內容展開 若標頭檔案中有遞迴包含逐級展開 ...

游標那點事兒

兩種迴圈跳出方法 1 稍顯複雜點 create procedure dbo.usp cralltables client id varchar 256 asdeclare table name varchar 50 set nocount on declare t name cur cursor l...

imu那點事兒

一.對於bosch晶元的總結 offset 是指sensor的零偏。datasheet 裡邊描述的是在不同的情況下offset 的spec.offa,int 表示sensor 出廠時最初的offset spec,是component level offa,board 表示sensor 在貼到pcb ...