一、巨集定義
1. 巨集定義的作用域
巨集定義開始,到檔案結束(其他的檔案包含巨集定義的檔案也可引用)。
2. 巨集定義可增加**的可讀性
#define error_poweroff -1
若不採用巨集定義的方式,**中出現-1 時,程式的可讀性變差,**中出現有具體的含義的單獨的數字(比如上面-1) 稱為魔鬼數,別人閱讀**的時候會抓狂,恐怕自己閱讀的時候,也不知具體的含義
3. 巨集預編譯階段巨集定義替換**中具體的定義
這點**中定義比較容易出錯,比如
(1)#define sqr (x) x * x
當表示式 x = 10+1, sqr(x) * sqr(x) 替換為 10+1*10+1,顯然這不是我們想要的結果,導致出錯
(2)#define add (x) (x)+(x)
當表示式 x=5, add(x)*add(x) 替換為 (5)+(5)*(5)+5,顯然這不是我們想要的結果,導致出錯
解析:避免這種錯誤,當巨集定義的時候,每部分都加上括號:(1))#define sqr (x) ((x) *( x)) (2)#define add (x) ((x)+(x))
4. 當巨集出現在字串中的時候,巨集不會被替換
比如 printf("add(x)"); 列印的結果為 add(x) 而不是 (x)+(x)
5. 巨集定義函式的時候,函式識別符號和引數之間不能有空格
比如 #define sqr (x) x * x , 巨集將變成**中用(x) x * x 替換**中的sqr ;
但引用巨集的時候可以有空格,比如 #define add (x) ((x)+(x)), 應用的時候 add (3) 和 add(3) 都是正確的
6. 取消巨集定義的符號 #undef,此符號之後的巨集的定義將不再起作用
二、條件編譯
條件編譯的形式之一:
(1) #ifdef 識別符號
程式段1
#else
程式段2
#endif
(2) #if 常量表示式
程式段1
#else
程式段2
#endif
條件編譯應用於場景之一,比如當在windows平台下編寫**除錯,而程式又是可以執行在linux或者aix平台下,這樣可以進行條件編譯;
條件編譯和 if--else if---else if .....else 語句一樣可以有不同的引申
三、檔案包含#include
1. 檔案包含是預處理的乙個重要功能,它可用來把多個原始檔連線成乙個原始檔進行編譯,結果將生成乙個目標檔案。c語言提供#include 命令來實現檔案包含的操作,它實際是巨集定義的延伸;
(1)#include
c 編譯系統所提供的並存放在指定的子目錄下的標頭檔案。找到檔案後,用檔案內容替換該語句;
(2)#include 「filename」
預處理應在當前目錄中查詢檔案名為filename 的檔案,若沒有找到,則按系統指定的路徑資訊,搜尋其他目錄。找到檔案後,用檔案內容替換該語句。
#include 是將已存在檔案的內容嵌入到當前檔案中
2. #include 支援相對路徑
比如,#include "./filename" (當前目錄下的檔案filename) #include "./icp/filename"(上層路徑檔案icp目錄下的檔案filename)
四、#pragma comment(...)
該指令將乙個注釋記錄放入乙個物件檔案或可執行檔案中。常用的lib 關鍵字,可以幫我們連入乙個庫檔案。比如:
#pragma comment(lib, "user32.lib")
該指令用來將user32.lib 庫檔案加入到本工程中。
linker:將乙個鏈結選項放入目標檔案中,你可以使用這個指令來代替由命令列傳入的或 者在開發環境中設定的鏈結選項,你可以指定/include 選項來強制包含某個物件,
例如:#pragma comment(linker, "/include:__mysymbol")
五、#pragma warning
#pragma warning( disable : 4507 34; once : 4385; error : 164 )
等價於:
#pragma warning(disable:4507 34) // 不顯示4507 和34 號警告資訊
#pragma warning(once:4385) // 4385 號警告資訊僅報告一次
#pragma warning(error:164) // 把164 號警告資訊作為乙個錯誤。
不過程式設計的時候,盡量少用disable,盡量在編碼的時候,將warning問題解決掉,有的時候warning 也是潛在的bug
六、#pragma once
在標頭檔案的最開始加入這條指令就能夠保證標頭檔案被編譯一次
另外保證標頭檔案只編譯一次的方法:
#ifndef _filename_h
#define _filename_h
#endif
七、#pragma code_seg
另乙個使用得比較多的pragma 引數是code_seg。格式如:
#pragma code_seg( ["section-name"[,"section-class"] ] )
它能夠設定程式中函式**存放的**段,當我們開發驅動程式的時候就會使用到它
八、#pragma message
能夠在編譯資訊輸出視窗中輸出相應的資訊,這對於源**資訊的控制是非常重要的。其使用方法為:
#pragma message(「訊息文字")
當編譯器遇到這條指令時就在編譯輸出視窗中將訊息文字列印出來。 這對於我們進行原始碼控制,**除錯有幫助。
九、記憶體對齊 #pragma pack
1. 記憶體對齊的原理:
字,雙字,和四字在自然邊界上不需要在記憶體中對齊。(對字,雙字,和四字來說,自然邊界分別是偶數字址,可以被4 整除的位址,和可以被8 整除的位址)無論如
何,為了提高程式的效能,資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;然而,對齊的記憶體
訪問僅需要一次訪問。減少記憶體位址匯流排訪問未對齊的位址的週期。
2. 記憶體對齊例子
(1)struct teststruct1
;解析:此結構體在記憶體中的布局為 1*,11,1*******,1111 (1 代表占用記憶體,* 代表為記憶體對齊補的記憶體空間)
所以 sizeof(teststruct1) 為12
3. 記憶體對齊的避免
可以在程式設計的時候,盡量避免記憶體對齊的情況,盡量自然對齊節省占用記憶體空間,比如上例
struct teststruct2
;sizeof(teststruct2) 為 8
4.
#pragma pack
#pragma pack (n),編譯器將按照n 個位元組對齊
#pragma pack (),編譯器將取消自定義位元組對齊方式 例如
#pragma pack(8)
struct teststruct4
;struct teststruct5
;#pragma pack()
解析:
teststruct4 記憶體布局: 1***,1111
teststruct5 記憶體布局: 1***,1***,1111****,11111111
所以 sizeof(teststruct4) 為 8,sizeof(teststruct5)為 24
5. 記憶體對齊的規則
(1)每個成員分別按自己的方式對齊,並能最小化長度
(2)複雜型別(如結構)的預設對齊方式是它最長的成員的對齊方式,這樣在成員是複雜型別時,可以最小化長度
(3)對齊後的長度必須是成員中最大的對齊引數的整數倍,這樣在處理陣列時可以保證每一項都邊界對齊
(4)對於陣列,比如:char a[3];它的對齊方式和分別寫3 個char 是一樣的.也就是說它還是按1 個位元組對齊,即陣列按照陣列中的每個成員的型別對齊
如果寫: typedef char array3[3];array3 這種型別的對齊方式還是按1 個位元組對齊,而不是按它的長度
(5)不論型別是什麼,對齊的邊界一定是1,2,4,8,16,32,64....中的乙個
十、#預算符
1. # 符號的用處之一: 將巨集中字串中的變數,以變數值的形式列印
(1)比如:
#define sqr(x) printf("the square of x is %d.\n", ((x)*(x)));
如果這樣使用巨集:sqr(8);
則輸出為:
the square of x is 64.
(2) 修改上面的巨集為:
#define sqr(x) printf("the square of "#x" is %d.\n", ((x)*(x)));
再使用:
sqr(8);
則輸出的是:
the square of 8 is 64.
十一、##預算符
##預算符作用:粘合劑
#define display(n) x ## n
如果這樣使用巨集:
display(8)
則會被展開成這樣:
x8
C語言深度解剖 預處理
1 line 表示正在編譯的檔案的行號,2 file 表示正在編譯的檔案的名字,3 date 表示編譯時刻的日期字串,4 time 表示編譯時刻的時間字串,5 stdc 判斷該檔案是不是定義成標準c程式。一 巨集定義 1 數值巨集常量 define pi 3.141592654 define err...
c語言整理編譯預處理
c程式執行過程 源程式 編譯預處理 編譯 優化程式 匯程式設計序 鏈結程式 可執行檔案。編譯預處理時,先要讀取源程式,對預處理指令 開頭指令 以及特殊的符號進行處理,比如define 替換指令,也會進行刪除注釋,多餘的空白字元,然後產生的預處理檔案或者程式傳給編譯器,在程式中以 開頭的編譯指令稱為預...
C語言深度剖析
c語言深度剖析 1,編譯器通常不為普通const唯讀變數分配儲存空間,而是將他們儲存在符號表中,使得它成為乙個編譯期間的值,沒有了儲存與讀記憶體的操作,使得它的效率更高。2,const int p p可變,p指向的物件不變。int const p p可變,p指向的物件不可變 int const p ...