預處理
- 文章標題提到的三個概念常常和預處理緊密聯繫的,所以我們先了解一下程序編譯的預處理的步驟。
-
所謂預處理是指程序進行編譯過程的第一個階段。系統會自動將’#'開頭的預處理部分做進行處理,處理完畢後進行進入源程序的編譯階段。它主要處理像宏替換,文件包含、條件編譯等部分。
-
C語言中提供多種預處理功能,如宏定義、文件包含、條件編譯等。
-
宏定義
-
在C語言源程序中允許用一個標識符表示符號,稱爲宏,被定義爲宏的標識符稱爲宏名。對程序中出現的所有宏名,都用宏定義中的符號串去替換,這稱爲宏替換或者宏展開。
-
常見的宏定義符號表:
符號 實例 含義 _FILE_ 正在預編譯源文件名 _LINE_ 文件在當前的行號 _FUNCTION_ 當前所在的函數名 _DATE_ 預編譯文件的日期 _TIME_ 預編譯文件的時間 _STDC_ 如果編譯器遵循ANSIC,則值爲1
-
- 宏定義
- 宏替換是在預處理時自動完成的
1.無參宏定義
#define 標識符 字符串
- 宏定義用宏名來表示一串字符串符號,在宏展開的時候又以該符號去替代宏名,這只是一種簡單的替換。
- 宏定義不是聲明或語句,在行末不必加分號,如加上分號會連分號一起替換
- 宏定義的作用域從從宏定義命名起到源程序結束,如要終止其作用域可使用#undef命令來取消宏作用域。
- 宏名在源程序中若用引號括起來則預處理程序則不對其進行宏替換。
- 習慣上宏名一般用大寫字母。
- 可對輸出格式做宏定義,減少麻煩。
2.帶參宏定義
-
C語言中允許宏帶有參數,在宏定義中的參數被稱爲形式參數,在宏調用中的參數稱爲實際參數。對帶參數的宏在調用時不僅要宏展開,而且還要用實參去替換形參。一般形式如下:
#define 宏名(形參表) 字符串
-
帶參宏定義中,宏名和參數表之間不能有空格出現。
#define MAX (a,b) (a>b)?a:b //錯誤例子
這將會被認爲是無參宏定義,宏名MAX代表字符串"(a,b) (a>b)?a:b"。
-
在帶參宏定義中,形式參數不分配內存單元,因此不必做類型定義。這與函數中的情況是不同的,在函數中,形參和實參是兩個不同的量,各自有各自的作用域,調用時要把實參值賦給形參,進行值傳遞。而在帶參數宏定義中只是符號替換不存在值傳遞的問題。
-
在宏定義中,形參是標識符,而宏調用中的實參可以是表達式。這與函數調用是不同的,函數調用時要把實參表達式的值求出來再賦予形參,而宏替換中對實參表達式不做計算直接原樣替換。(爲避免引起問題,應該在採納數兩側加括號,還應在整個符號串外加括號)。
- 文件包含
-
文件包含語句的功能是把指定的文件插入該語句行位置,從而把指定的文件和當前源程序文件連成一個源文件。
-
包含形式如下:
#include "文件名" #include <文件名>
-
這兩種包含形式的不同點:
1.使用<>表示的在系統頭文件目錄去查找(頭文件目錄可以由用戶來指定)。
2.使用雙引號則表示首先在當前源文件的目錄查找,若未找到纔到系統頭文件目錄去查找。
- 一個include命令只能包含一個指定的文件。
-
文件包含允許嵌套,也就是說如果我們包含的文件中若包含了其他文件,則該文件也是被我們當前文件所包含着的。
-
-
條件編譯
-
使編譯器按照不同的條件去編譯不同的代碼,主要由一下三種形式:
#ifdef 標識符 程序段1 #else 程序段2 #endif
它表示如果標識符已經被#define語句定義過,則編譯程序段1,否則編譯程序段2,。如果沒有程序段2,則本格式中的#else可以沒有。
#ifndef 標識符 程序段1 #else 程序段2 #endif
與第一種形式的功能正好相反。
#if 常量表達式 程序段1 #else 程序段2 #endif
它的功能是,如果常量表達式的值爲真(非0),則編譯程序段1,否則編譯程序段2。因此可以是程序在不同的條件下完成不同的編譯的功能。這個特性在很多大型程序中應用比較廣泛。
-