指令 用途 程序員
# 空指令,無任何效果
#include 包含一個源代碼文件
#define 定義宏
#undef 取消已定義的宏
#if 若是給定條件爲真,則編譯下面代碼
#ifdef 若是宏已經定義,則編譯下面代碼
#ifndef 若是宏沒有定義,則編譯下面代碼
#elif 若是前面的#if給定條件不爲真,當前條件爲真,則編譯下面代碼
#endif 結束一個#if……#else條件編譯塊
#error 中止編譯並顯示錯誤信息 數組
1、文件包含
爲了不那些只能包含一次的頭文件被屢次包含,能夠在頭文件中用編譯時條件來進行控制。例如: 安全
#ifndef MY_H
#define MY_H
……
#endif 函數
2、宏
1.#define指令
#define預處理指令是用來定義宏的。該指令最簡單的格式是:首先神明一個標識符,而後給出這個標識符表明的代碼。在後面的源代碼中,就用這些代碼來替代該標識符。這種宏把程序中要用到的一些全局值提取出來,賦給一些記憶標識符。
#define MAX_NUM 10
int array[MAX_NUM];
for(i=0;i<MAX_NUM;i++)
在這個例子中,對於閱讀該程序的人來講,符號MAX_NUM就有特定的含義,它表明的值給出了數組所能容納的最大元素數目。程序中能夠屢次使用這個值。做爲一種約定,習慣上老是所有用大寫字母來定義宏,這樣易於把程序紅的宏標識符和通常變量標識符區別開來。若是想要改變數組的大小,只須要更改宏定義並從新編譯程序便可。
宏表示的值能夠是一個常量表達式,其中容許包括前面已經定義的宏標識符。例如:
#define ONE 1
#define TWO 2
#define THREE (ONE+TWO)
注意上面的宏定義使用了括號。儘管它們並非必須的。但出於謹慎考慮,仍是應該加上括號的。例如:
six=THREE*TWO;
預處理過程把上面的一行代碼轉換成:
six=(ONE+TWO)*TWO;
若是沒有那個括號,就轉換成six=ONE+TWO*TWO;了。
宏還能夠表明一個字符串常量,例如:
#define VERSION "Version 1.0 Copyright(c) 2003"
2.帶參數的#define指令
帶參數的宏和函數調用看起來有些類似。看一個例子:
#define Cube(x) (x)*(x)*(x)
能夠時任何數字表達式甚至函數調用來代替參數x。這裏再次提醒你們注意括號的使用。宏展開後徹底包含在一對括號中,並且參數也包含在括號中,這樣就保證了宏和參數的完整性。看一個用法:
int num=8+2;
volume=Cube(num);
展開後爲(8+2)*(8+2)*(8+2);
若是沒有那些括號就變爲8+2*8+2*8+2了。
下面的用法是不安全的:
volume=Cube(num++);
若是Cube是一個函數,上面的寫法是能夠理解的。可是,由於Cube是一個宏,因此會產生反作用。這裏的擦書不是簡單的表達式,它們將產生意想不到的結果。它們展開後是這樣的:
volume=(num++)*(num++)*(num++);
很顯然,結果是10*11*12,而不是10*10*10;
那麼怎樣安全的使用Cube宏呢?必須把可能產生反作用的操做移到宏調用的外面進行:
int num=8+2;
volume=Cube(num);
num++;
3.#運算符
出如今宏定義中的#運算符把跟在其後的參數轉換成一個字符串。有時把這種用法的#稱爲字符串化運算符。例如: this
#define PASTE(n) "adhfkj"#n spa
main()
{
printf("%s\n",PASTE(15));
}
宏定義中的#運算符告訴預處理程序,把源代碼中任何傳遞給該宏的參數轉換成一個字符串。因此輸出應該是adhfkj15。
4.##運算符
##運算符用於把參數鏈接到一塊兒。預處理程序把出如今##兩側的參數合併成一個符號。看下面的例子: debug
#define NUM(a,b,c) a##b##c
#define STR(a,b,c) a##b##c 字符串
main()
{
printf("%d\n",NUM(1,2,3));
printf("%s\n",STR("aa","bb","cc"));
} 編譯器
最後程序的輸出爲:
123
aabbcc
千萬別擔憂,除非須要或者宏的用法剛好和手頭的工做相關,不然不多有程序員會知道##運算符。絕大多數程序員歷來沒用過它。 io
3、條件編譯指令
條件編譯指令將決定那些代碼被編譯,而哪些是不被編譯的。能夠根據表達式的值或者某個特定的宏是否被定義來肯定編譯條件。
1.#if指令
#if指令檢測跟在製造另關鍵字後的常量表達式。若是表達式爲真,則編譯後面的代碼,知道出現#else、#elif或#endif爲止;不然就不編譯。
2.#endif指令
#endif用於終止#if預處理指令。
#define DEBUG 0
main()
{
#if DEBUG
printf("Debugging\n");
#endif
printf("Running\n");
}
因爲程序定義DEBUG宏表明0,因此#if條件爲假,不編譯後面的代碼直到#endif,因此程序直接輸出Running。
若是去掉#define語句,效果是同樣的。
3.#ifdef和#ifndef
#define DEBUG
main()
{
#ifdef DEBUG
printf("yes\n");
#endif
#ifndef DEBUG
printf("no\n");
#endif
}
#if defined等價於#ifdef; #if !defined等價於#ifndef
4.#else指令
#else指令用於某個#if指令以後,當前面的#if指令的條件不爲真時,就編譯#else後面的代碼。#endif指令將中指上面的條件塊。
#define DEBUG
main()
{
#ifdef DEBUG
printf("Debugging\n");
#else
printf("Not debugging\n");
#endif
printf("Running\n");
}
5.#elif指令
#elif預處理指令綜合了#else和#if指令的做用。
#define TWO
main()
{
#ifdef ONE
printf("1\n");
#elif defined TWO
printf("2\n");
#else
printf("3\n");
#endif
}
程序很好理解,最後輸出結果是2。
6.其餘一些標準指令
#error指令將使編譯器顯示一條錯誤信息,而後中止編譯。
#line指令能夠改變編譯器用來指出警告和錯誤信息的文件號和行號。
#pragma指令沒有正式的定義。編譯器能夠自定義其用途。典型的用法是禁止或容許某些煩人的警告信息。
gcc的-D和-U參數:宏的設置與取消
這兩天作LFS注意到了gcc的-D參數:在gcc命令中定義宏,好比我有以下的代碼:
/* hello.c */
#include
#ifdef YES
char* str = "Yes, this is a macro.";
#else
char* str = "No, there is no macro.";
#endif
int main()
{
printf("%s\n", str);
return 0;
}
使用-D傳入宏YES來進行編譯:
recordus@LFS test # gcc -DYES -o helloyes hello.c
recordus@LFS test # ./helloyes
Yes, this is a macro.
而不傳入宏則是這樣的:
recordus@LFS test # gcc -o hellono hello.c
recordus@LFS test # ./hellono
No, there is no macro.
gcc還有與-D對應的另外一個參數-U用於取消宏,好比:
root@LFS test # gcc -DYES -UYES -o helloyesno hello.c
root@LFS test # ./helloyesno
No, there is no macro.
這大概是這兩個參數最簡單的應用了:)