1. 程式人生 > >C Primer Plus--C前處理器和C庫(2)

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);
 *}
 */

無法獲取行內函數的地址,因為行內函數並沒有被分配單獨的空間。行內函數適用於短小函式,長的函式呼叫造成的時間遠遠小於函式體執行時間,使用行內函數並沒什麼意義。
行內函數的定義和對該函式的呼叫必須在同一檔案中。因此,行內函數一般具有內部連結。在多檔案程式中,要想使用相同的行內函數,必須在每個檔案中對行內函數進行定義。為了方便,可以把行內函數的定義放在標頭檔案中。