C Primer Plus--C前處理器和C庫(2)
目錄
#include指令
- #include <標頭檔案.h>//在標準系統目錄中尋找標頭檔案
- #include "標頭檔案.h"//先在當前目錄下面尋找標頭檔案,然後在標準系統目錄下尋找標頭檔案
前處理器在碰到#inclide
指令時,就會將後面附加的標頭檔案的內容包含到當前檔案中。
標頭檔案
字尾為.h
的檔案是標頭檔案。這類檔案經常包含前處理器所需要的語句。
標頭檔案內容最常見形式包括:
- 明顯常量
- 巨集函式
- 函式宣告
- 結構模板定義
- 型別定義
其他指令
#undef
#undef
指令取消一個給定的已定義#define
.
#define FF 10
#undef FF //FF定義被取消
條件編譯
#ifdef
#else
#endif
#ifdef
後面的識別符號如果已經定義了,那麼執行它的分支控制的指令,知道下一個#else
或#endif
為止。如果有#else
存在,那麼在未定義時會執行#else
知道#endif
之間的所有指令。
#define FF 10 #ifdef FF #define AA 100 #else #define AA 1000 #endif int main() { printf("FF :%d\n",AA); }
#ifndef
#ifndef
是#ifdef
的反義詞,它是用來確定後面的表示符未被定義。通常用來定義此前未被定義的常量。
#ifndef FF
#define FF 199
#endif
int main() {
printf("FF :%d\n",FF);
}
#ifndef
也可以用於防止多次包含同一檔案。
/* *假設這個標頭檔案是test.h */ //原本標頭檔案的內容直接寫,現在我們把標頭檔案的內容放到下面這樣的結構裡: #ifndef _TEST_H #define _TEST_H /* *#define和#endif之間存放標頭檔案的所有內容 */ #endif
來看看上面這段程式碼什麼意思:
首先,明確我們的目的:防止一個檔案被多次的include。為什麼會存在多次include呢?因為可能一個檔案會include多個檔案,而不同檔案有可能include同一個檔案,而在一個檔案中只能對一個檔案中include一次。舉個栗子:存在a.h
,b.h
,test.h
,有可能a.h
中有一個#include "test.h"
,同時b.c
中有兩行
#include "a.h"
#include "test.h"
這樣就出現了b.h
被包含了兩次,而C是不允許這樣的。上面用到#ifndef
就解決了這個問題。
當test.h
未被定義,也就是說這個標頭檔案被第一次包含了,會定義一個_TEST_H
的常量,但沒有body,因為我們不需要這個常量具有body。這時候標頭檔案裡的所有內容被前處理器執行。當test.h
被第二次包含時,前處理器檢測到已經存在_TEST_H
這個量,就會跳過,也就不會重複執行標頭檔案裡的內容了。這裡的關鍵是保持_TEST_H
的唯一。我們這裡用標頭檔案的檔名做識別符號,將檔名前面加下劃線,並將點換成下劃線,能夠保證這個識別符號不重複。但這種做法是編譯器提供商為了標準標頭檔案採用的方法,我們平時自己寫的時候要想防止與標準標頭檔案衝突,就不要按這種方法來取識別符號。例如可以把下劃線加到檔名後面等等。
#if
和#elif
#if
、#elif
後面跟常量整數表示式,當這個表示式值為非0值時為真,為0位假,類似於C程式中的if-else
分支結構。可以應用C的關係運算符以及邏輯運算子。
#if defined(FF)
#define SS 9999
#elif defined(_TEST_H)
#define EE 99
#endif
預定義巨集
一些常見的預定義巨集:
巨集 | 意義 |
---|---|
__DATE__ | 進行預處理操作的日期字串 |
__FILE__ | 當前原始碼檔名的字串 |
__LINE__ | 當前所在代買行號 |
__TIME__ | 原始檔編譯時間 |
__STDC_VERSION__ | 當前編譯器遵循的C標準版本,當為C99時值為199901L |
#line
和#error
#line
指令用於重置由__LINE__
和__FILE__
巨集報告的行號和檔名。
使用方法:
#line 100 //當前行號重置為100
#line 10 "test.c" //把行號重置為10,檔名重置為test.c
printf("%d\n",__LINE__);
#line 1000
printf("%d\n",__LINE__);
printf("%d\n",__LINE__);
#error
指令使前處理器發出一條錯誤訊息,該訊息包含指令中的文字。可能的話,編譯過程應該中斷。
#if __STDC_VERSION__ != 199901L
#error Not C99
#endif
行內函數
行內函數主要是為了把解決函式呼叫過程中建立呼叫、傳遞引數、跳轉到函式程式碼段返回耗費的時間較長的問題。它適用於較短程式碼塊,建立行內函數需要用到inline
關鍵字。
inline double square(double x);
double square(double x){
return x*x;
}
int main() {
double a = square(3);
printf("%lf\n",a);
}
//行內函數這裡其實把函式體直接寫到了main裡面,不用呼叫了。
/*
*int main(){
* double a = a * a;
* printf("%lf\n",a);
*}
*/
無法獲取行內函數的地址,因為行內函數並沒有被分配單獨的空間。行內函數適用於短小函式,長的函式呼叫造成的時間遠遠小於函式體執行時間,使用行內函數並沒什麼意義。
行內函數的定義和對該函式的呼叫必須在同一檔案中。因此,行內函數一般具有內部連結。在多檔案程式中,要想使用相同的行內函數,必須在每個檔案中對行內函數進行定義。為了方便,可以把行內函數的定義放在標頭檔案中。