# C 預處理器
**C 預處理器**不是編譯器的組成部分,但是它是編譯過程中一個單獨的步驟。簡言之,C 預處理器只不過是一個文本替換工具而已,他們會指示編譯器在實際編譯之前完成所需的預處理。我們將把 C 預處理器(C Preprocessor)簡寫為 CPP。
所有的預處理器命令都是以井號(#)開頭。它必須是第一個非空字符,為了增強可讀性,預處理器指令應從第一列開始。下面列出了所有重要的預處理器指令:
| 指令 | 描述 |
| --- | --- |
| #define | 定義宏 |
| #include | 包含一個源代碼文件 |
| #undef | 取消已定義的宏 |
| #ifdef | 如果宏已經定義,則返回真 |
| #ifndef | 如果宏沒有定義,則返回真 |
| #if | 如果給定條件為真,則編譯下面代碼 |
| #else | #if 的替代方案 |
| #elif | 如果前面的 #if 給定條件不為真,當前條件為真,則編譯下面代碼 |
| #endif | 結束一個 #if……#else 條件編譯塊 |
| #error | 當遇到標準錯誤時,輸出錯誤消息 |
| #pragma | 使用標準化方法,向編譯器發布特殊的命令到編譯器中 |
## 預處理器實例
分析下面的實例來理解不同的指令。
```
#define MAX_ARRAY_LENGTH 20
```
這個指令告訴 CPP 把所有的 MAX_ARRAY_LENGTH 替換為 20。使用 _#define_ 定義常量來增強可讀性。
```
#include <stdio.h>
#include "myheader.h"
```
這些指令告訴 CPP 從**系統庫**中獲取 stdio.h,并添加文本到當前的源文件中。下一行告訴 CPP 從本地目錄中獲取 **myheader.h**,并添加內容到當前的源文件中。
```
#undef FILE_SIZE
#define FILE_SIZE 42
```
這個指令告訴 CPP 取消已定義的 FILE_SIZE,并定義它為 42。
```
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
```
這個指令告訴 CPP 只有當 MESSAGE 未定義時,才定義 MESSAGE。
```
#ifdef DEBUG
/* Your debugging statements here */
#endif
```
這個指令告訴 CPP 如果定義了 DEBUG,則執行處理語句。在編譯時,如果您向 gcc 編譯器傳遞了 _-DDEBUG_ 開關量,這個指令就非常有用。它定義了 DEBUG,您可以在編譯期間隨時開啟或關閉調試。
## 預定義宏
ANSI C 定義了許多宏。在編程中您可以使用這些宏,但是不同直接修改這些預定義的宏。
| 宏 | 描述 |
| --- | --- |
| \_\_DATE\_\_ | 當前日期,一個以 "MMM DD YYYY" 格式表示的字符常量。 |
| \_\_TIME\_\_ | 當前時間,一個以 "HH:MM:SS" 格式表示的字符常量。 |
| \_\_FILE\_\_ | 這會包含當前文件名,一個字符串常量。 |
| \_\_LINE\_\_ | 這會包含當前行號,一個十進制常量。 |
| \_\_STDC\_\_ | 當編譯器以 ANSI 標準編譯時,則定義為 1。 |
讓我們來嘗試下面的實例:
```
#include <stdio.h>
main()
{
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
printf("ANSI :%d\n", __STDC__ );
}
```
當上面的代碼(在文件 **test.c** 中)被編譯和執行時,它會產生下列結果:
```
File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1
```
## 預處理器運算符
C 預處理器提供了下列的運算符來幫助您創建宏:
##### 宏延續運算符(\)
一個宏通常寫在一個單行上。但是如果宏太長,一個單行容納不下,則使用宏延續運算符(\)。例如:
```
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
```
##### 字符串常量化運算符(#)
在宏定義中,當需要把一個宏的參數轉換為字符串常量時,則使用字符串常量化運算符(#)。在宏中使用的該運算符有一個特定的參數或參數列表。例如:
```
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void)
{
message_for(Carole, Debra);
return 0;
}
```
當上面的代碼被編譯和執行時,它會產生下列結果:
```
Carole and Debra: We love you!
```
##### 標記粘貼運算符(##)
宏定義內的標記粘貼運算符(##)會合并兩個參數。它允許在宏定義中兩個獨立的標記被合并為一個標記。例如:
```
#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void)
{
int token34 = 40;
tokenpaster(34);
return 0;
}
```
當上面的代碼被編譯和執行時,它會產生下列結果:
```
token34 = 40
```
這是怎么發生的,因為這個實例會從編譯器產生下列的實際輸出:
```
printf ("token34 = %d", token34);
```
這個實例演示了 token##n 會連接到 token34 中,在這里,我們使用了**字符串常量化運算符(#)**和**標記粘貼運算符(##)**。
##### defined() 運算符
預處理器 **defined** 運算符是用在常量表達式中的,用來確定一個標識符是否已經使用 #define 定義過。如果指定的標識符已定義,則值為真(非零)。如果指定的標識符未定義,則值為假(零)。下面的實例演示了 defined() 運算符的用法:
```
#include <stdio.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void)
{
printf("Here is the message: %s\n", MESSAGE);
return 0;
}
```
當上面的代碼被編譯和執行時,它會產生下列結果:
```
Here is the message: You wish!
```
## 參數化的宏
CPP 一個強大的功能是可以使用參數化的宏來模擬函數。例如,下面的代碼是計算一個數的平方:
```
int square(int x) {
return x * x;
}
```
我們可以使用宏重寫上面的代碼,如下:
```
#define square(x) ((x) * (x))
```
在使用帶有參數的宏之前,必須使用 **#define** 指令定義。參數列表是括在圓括號內,且必須緊跟在宏名稱的后邊。宏名稱和左圓括號之間不允許有空格。例如:
```
#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
```
當上面的代碼被編譯和執行時,它會產生下列結果:
```
Max between 20 and 10 is 20
```
- C語言教程
- C 簡介
- C 環境設置
- C 程序結構
- C 基本語法
- C 數據類型
- C 變量
- C 常量
- C 存儲類
- C 運算符
- C 判斷
- C 循環
- C 函數
- C 作用域規則
- C 數組
- C 指針
- C 字符串
- C 結構體
- C 共用體
- C 位域
- C typedef
- C 輸入 & 輸出
- C 文件讀寫
- C 預處理器
- C 頭文件
- C 強制類型轉換
- C 錯誤處理
- C 遞歸
- C 可變參數
- C 內存管理
- C 命令行參數
- C語言參考
- C 標準庫 - <assert.h>
- C 庫宏 - assert()
- C 標準庫 - <ctype.h>
- C 庫函數 - isalnum()
- C 庫函數 - isalpha()
- C 庫函數 - iscntrl()
- C 庫函數 - isdigit()
- C 庫函數 - isgraph()
- C 庫函數 - islower()
- C 庫函數 - isprint()
- C 庫函數 - ispunct()
- C 庫函數 - isspace()
- C 庫函數 - isupper()
- C 庫函數 - isxdigit()
- C 標準庫 - <errno.h>
- C 庫宏 - errno
- C 庫宏 - EDOM
- C 庫宏 - ERANGE
- C 標準庫 - <float.h>
- C 標準庫 - <limits.h>
- C 標準庫 - <locale.h>
- C 庫函數 - setlocale()
- C 庫函數 - localeconv()
- C 標準庫 - <math.h>
- C 庫函數 - acos()
- C 庫函數 - asin()
- C 庫函數 - atan()
- C 庫函數 - atan2()
- C 庫函數 - cos()
- C 庫函數 - cosh()
- C 庫函數 - sin()
- C 庫函數 - sinh()
- C 庫函數 - tanh()
- C 庫函數 - exp()
- C 庫函數 - frexp()
- C 庫函數 - ldexp()
- C 庫函數 - log()
- C 庫函數 - log10()
- C 庫函數 - modf()
- C 庫函數 - pow()
- C 庫函數 - sqrt()
- C 庫函數 - ceil()
- C 庫函數 - fabs()
- C 庫函數 - floor()
- C 庫函數 - fmod()
- C 標準庫 - <setjmp.h>
- C 庫宏 - setjmp()
- C 庫函數 - longjmp()
- C 標準庫 - <signal.h>
- C 庫函數 - signal()
- C 庫函數 - raise()
- C 標準庫 - <stdarg.h>
- C 庫宏 - va_start()
- C 庫宏 - va_arg()
- C 庫宏 - va_end()
- C 標準庫 - <stddef.h>
- C 庫宏 - NULL
- C 庫宏 - offsetof()
- C 標準庫 - <stdio.h>
- C 庫函數 - fclose()
- C 庫函數 - clearerr()
- C 庫函數 - feof()
- C 庫函數 - ferror()
- C 庫函數 - fflush()
- C 庫函數 - fgetpos()
- C 庫函數 - fopen()
- C 庫函數 - fread()
- C 庫函數 - freopen()
- C 庫函數 - fseek()
- C 庫函數 - fsetpos()
- C 庫函數 - ftell()
- C 庫函數 - fwrite()
- C 庫函數 - remove()
- C 庫函數 - rename()
- C 庫函數 - rewind()
- C 庫函數 - setbuf()
- C 庫函數 - tmpfile()
- C 庫函數 - tmpnam()
- C 庫函數 - fprintf()
- C 庫函數 - printf()
- C 庫函數 - sprintf()
- C 庫函數 - vfprintf()
- C 庫函數 - vprintf()
- C 庫函數 - vsprintf()
- C 庫函數 - fscanf()
- C 庫函數 - scanf()
- C 庫函數 - sscanf()
- C 庫函數 - fgetc()
- C 庫函數 - fgets()
- C 庫函數 - fputc()
- C 庫函數 - fputs()
- C 庫函數 - getc()
- C 庫函數 - getchar()
- C 庫函數 - gets()
- C 庫函數 - putc()
- C 庫函數 - putchar()
- C 庫函數 - puts()
- C 庫函數 - ungetc()
- C 庫函數 - perror()
- C 標準庫 - <stdlib.h>
- C 庫函數 - atof()
- C 庫函數 - atoi()
- C 庫函數 - atol()
- C 庫函數 - strtod()
- C 庫函數 - strtol()
- C 庫函數 - strtoul()
- C 庫函數 - calloc()
- C 庫函數 - free()
- C 庫函數 - malloc()
- C 庫函數 - realloc()
- C 庫函數 - abort()
- C 庫函數 - atexit()
- C 庫函數 - exit()
- C 庫函數 - getenv()
- C 庫函數 - system()
- C 庫函數 - bsearch()
- C 庫函數 - qsort()
- C 庫函數 - abs()
- C 庫函數 - div()
- C 庫函數 - labs()
- C 庫函數 - ldiv()
- C 庫函數 - rand()
- C 庫函數 - srand()
- C 庫函數 - mblen()
- C 庫函數 - mbstowcs()
- C 庫函數 - mbtowc()
- C 庫函數 - wcstombs()
- C 庫函數 - wctomb()
- C 標準庫 - <string.h>
- C 庫函數 - memchr()
- C 庫函數 - memcmp()
- C 庫函數 - memcpy()
- C 庫函數 - memmove()
- C 庫函數 - memset()
- C 庫函數 - strcat()
- C 庫函數 - strncat()
- C 庫函數 - strchr()
- C 庫函數 - strcmp()
- C 庫函數 - strncmp()
- C 庫函數 - strcoll()
- C 庫函數 - strcpy()
- C 庫函數 - strncpy()
- C 庫函數 - strcspn()
- C 庫函數 - strerror()
- C 庫函數 - strlen()
- C 庫函數 - strpbrk()
- C 庫函數 - strrchr()
- C 庫函數 - strspn()
- C 庫函數 - strstr()
- C 庫函數 - strtok()
- C 庫函數 - strxfrm()
- C 標準庫 - <time.h>
- C 庫函數 - asctime()
- C 庫函數 - clock()
- C 庫函數 - ctime()
- C 庫函數 - difftime()
- C 庫函數 - gmtime()
- C 庫函數 - localtime()
- C 庫函數 - mktime()
- C 庫函數 - strftime()
- C 庫函數 - time()
- 免責聲明