預(yù)處理也稱為預(yù)編譯,它為編譯做預(yù)備工作,主要進行代碼文本的替換工作,用于處理#開頭的指令液茎。
1. C/C++頭文件中ifdef/define/endif的作用有哪些?
如果一個項目中存在兩個C文件辞嗡,而這兩個文件都包含同一個頭文件捆等。當(dāng)編譯時,這兩個文件編譯成一個可執(zhí)行文件可能會產(chǎn)生大量的聲明沖突续室。而解決的辦法就是把頭文件的內(nèi)容都放在#ifndef和#endif中栋烤,格式如下:
`#ifndef <_STDIO_H_>
#define <_STDIO_H_>
...
#endif
標識的命名規(guī)則一般是頭文件全大寫,前后加下劃線挺狰,并把文件中的“.”明郭,也變成下劃線,如stdio.h丰泊。
2. #define有哪些缺陷薯定?
由于宏定義在預(yù)處理階段進行,主要做的是字符串替換工作趁耗,所以它存在一些固有的缺陷:
- 無法進行類型檢查。宏定義是在編譯前進行字符替換疆虚,因為只有編譯時才能檢查類型是否匹配苛败,所以不具有類型檢查功能。
- 由于優(yōu)先級的不同是喲宏定義可能會存在著副作用径簿。
- 無法單步調(diào)試
- 會導(dǎo)致代碼膨脹
- 在C++中罢屈,宏無法操作類的私有成員。
3. 如何判斷一個變量是有符號數(shù)還是無符號數(shù)篇亭?
- 方法一:
#define ISUNSIGNED(a) (a>=0 && ~a>=0)
#define ISUNSIGNED_TYPE(type) ((type) - 1 > 0)
- 方法二:
typedef unsigned type;
int main(){
unsigned a = 10;
a = a | (1 << 31);
if(a > 0)
printf("signed\n");
else
printf("unsigned\n");
}
- 方法三:
typedef unsigned type;
int main(){
type a = -1, b = 100;
if(a - b > 0)
printf("signed\n");
else
printf("unsigned\n");
}
4. 不使用sizeof缠捌,如何計算int占用字節(jié)數(shù),以及結(jié)構(gòu)體內(nèi)存偏移量译蒂?
#define OFFSET(type, field) ((size_t)& ( ((type*)0)->field ) )
ANSI C標準允許值為0的常量強制被轉(zhuǎn)換為任何一種類型的指針曼月,且轉(zhuǎn)換結(jié)果為空指針。對0取(type*)的結(jié)果是將其轉(zhuǎn)化為指針type的空指針柔昼。雖然利用它來訪問field字段是非法的哑芹,但是由于宏替換發(fā)生在編譯前,編譯器僅僅是根據(jù)結(jié)構(gòu)體內(nèi)容布局捕透,計算出field相對于地址為0的指針的偏移量聪姿。
5. 枚舉碴萧、typedef 、const與宏定義有何不同末购?
枚舉可以定義大量相關(guān)常量破喻,具有自動賦值功能,枚舉常量是實體的一種盟榴,擁有作用域曹质、值等特征。此外曹货,枚舉常量在編譯階段確定其值咆繁,在編譯器中一般可以調(diào)試枚舉常量,這些特征都是宏定義所不具備的顶籽。
typedef可以為對象(基本類型或自定義類型)取一個別名玩般,以增加可讀性。其具有類型檢查功能礼饱,以及作用域坏为。宏定義只是簡單替換,不具備上述特點镊绪。值得注意的是匀伏,typedef和宏定義在處理指針時,區(qū)別較大蝴韭。
const常量具有數(shù)據(jù)類型够颠,存在于程序的數(shù)據(jù)段,可以被傳遞調(diào)用榄鉴。編譯器可以對const常量進行安全檢查履磨。因此,很多IDE支持const常量庆尘,而不支持宏定義剃诅。
6. 宏定義與內(nèi)聯(lián)函數(shù)有什么區(qū)別?
宏代碼本身不是函數(shù)驶忌,但是用起來卻和函數(shù)很像矛辕,預(yù)處理器用復(fù)制宏代碼的方式代替函數(shù)調(diào)用,省去了參數(shù)壓棧付魔、生成匯編語言的CALL調(diào)用聊品,返回參數(shù)、執(zhí)行return等過程几苍,從而提高了速度杨刨。
內(nèi)聯(lián)函數(shù)是代碼被插入到調(diào)用者代碼處的函數(shù)。內(nèi)聯(lián)函數(shù)也不是萬能的擦剑,只適用于函數(shù)體內(nèi)代碼簡單的函數(shù)使用妖胀,不包含復(fù)雜的結(jié)構(gòu)控制語句芥颈,并且內(nèi)聯(lián)函數(shù)本身不能直接調(diào)用遞歸函數(shù)。
兩者的區(qū)別在于:
- 宏定義是在預(yù)處理階段進行代碼替換的赚抡,而內(nèi)聯(lián)函數(shù)是在編譯階段插入代碼
- 宏定義沒有類型檢查爬坑,而內(nèi)聯(lián)函數(shù)有類型檢查。
引申:內(nèi)聯(lián)函數(shù)與普通函數(shù)的區(qū)別涂臣?
C++語言中的內(nèi)聯(lián)函數(shù)與普通函數(shù)相同盾计,但是編譯器會在每處調(diào)用內(nèi)聯(lián)函數(shù)的地方將內(nèi)聯(lián)函數(shù)展開,這樣既避免了函數(shù)調(diào)用的開銷赁遗,又避免了宏機制的缺陷署辉。在N處調(diào)用了內(nèi)聯(lián)函數(shù),則此函數(shù)就會對該段代碼展開N次岩四。如果內(nèi)聯(lián)函數(shù)體過大哭尝,編譯器則會放棄內(nèi)聯(lián)方式。