C語言預編譯 巨集的整理

2021-08-09 06:29:50 字數 4439 閱讀 5098

#define

null

0#define

null

/* null pointer */0``

`上面的重定義是相同的, 但下面的重定義不同:

如果多次定義時, 再次定義的巨集內容是不同的, gcc會給出」name redefined」警告資訊.

應該避免重新定義函式巨集, 不管是在預處理命令中還是c語句中, 最好對某個物件只有單一的定義. 在gcc中, 若巨集出現了重定義, gcc會給出警告.

(2) 在gcc中, 可在命令列中指定物件巨集的定義: e.g. $ gcc -wall -dmax=100 -o tmp tmp.c 相當於在tmp.c中新增」 #define max 100」.

那麼, 如果原先tmp.c中含有max巨集的定義, 那麼再在gcc呼叫命令中使用-dmax, 會出現什麼情況呢?

—若-dmax=1, 則正確編譯.

—若-dmax的值被指定為不為1的值, 那麼gcc會給出max巨集被重定義的警告, max的值仍為1.

注意: 若在呼叫gcc的命令列中不顯示地給出物件巨集的值, 那麼gcc賦予該巨集預設值(1), 如: -dval == -dval=1

(3) #define所定義的巨集的作用域 巨集在定義之後才生效, 若巨集定義被#undef取消, 則#undef之後該巨集無效. 並且字串中的巨集不會被識別 e.g.

char c = 「two」 /* c = 「two」, not 「2」! */

(4) 巨集的替換可以是遞迴的, 所以可以巢狀定義巨集. e.g.

int a = one /* a = 1 */ 「`

2, #undef

3, #if, #elif, #else, #endif

使用它們可以提公升**的可移植性—針對不同的平台使用執行不同的語句. 也經常用於大段**注釋. e.g.

常量表示式可以是包含巨集, 算術運算, 邏輯運算等等的合法c常量表示式, 如果常量表示式為乙個未定義的巨集, 那麼它的值被視為0.

注意: #if, #elif, #else之後的巨集只能是物件巨集. 如果name為名的巨集未定義, 或者該巨集是函式巨集. 那麼在gcc中使用」-wundef」選項會顯示巨集未定義的警告資訊.

4, #ifdef, #ifndef, defined.

它們經常用於避免標頭檔案的重複引用:

defined(name): 若巨集被定義,則返回1, 否則返回0. 它與#if, #elif, #else結合使用來判斷巨集是否被定義, 乍一看好像它顯得多餘, 因為已經有了#ifdef和#ifndef. defined用於在一條判斷語句中宣告多個判別條件:

和#if, #elif, #else不同, #indef, #ifndef, defined測試的巨集可以是物件巨集, 也可以是函式巨集. 在gcc中使用」-wundef」選項不會顯示巨集未定義的警告資訊.

5, #include , #include_next

實際上, 真正被新增的標頭檔案並不一定就是#include中所指定的檔案.

關於#include 「headfile」和#include 的區別以及如何在gcc中包含標頭檔案的詳細資訊, 參考本blog的gcc筆記.

相對於#include, 我們對#include_next不太熟悉.

可參考cpp手冊進一步了解#include_next

6, 預定義巨集 標準c中定義了一些物件巨集, 這些巨集的名稱以」__」開頭和結尾, 並且都是大寫字元. 這些預定義巨集可以被#undef, 也可以被重定義.

下面列出一些標準c中常見的預定義物件巨集(其中也包含gcc自己定義的一些預定義巨集:

line當前語句所在的行號, 以10進製整數標註.

file當前原始檔的檔名, 以字串常量標註.

date程式被編譯的日期, 以」mmm dd yyyy」格式的字串標註.

time程式被編譯的時間, 以」hh:mm:ss」格式的字串標註, 該時間由asctime返回.

stdc如果當前編譯器符合iso標準, 那麼該巨集的值為1

stdc_version如果當前編譯器符合c89, 那麼它被定義為199409l, 如果符合c99, 那麼被定義為199901l. 我用gcc, 如果不指定-std=c99, 其他情況都給出stdc_version未定義的錯誤資訊, 咋回事呢?

stdc_hosted如果當前系統是」本地系統(hosted)」, 那麼它被定義為1. 本地系統表示當前系統擁有完整的標準c庫.

gcc定義的預定義巨集:

optmize如果編譯過程中使用了優化, 那麼該巨集被定義為1.

optmize_size同上, 但僅在優化是針對**大小而非速度時才被定義為1.

version顯示所用gcc的版本號. 可參考」gcc the complete reference」. 要想看到gcc所定義的所有預定義巨集, 可以執行: $ cpp -dm /dev/null

7, #line

printf(「line: %d, file: %s\n」,line,file);

顯示: line: 34, file: 1.c line: 100, file: haha line: 101, file: haha

8, #pragma, _pragma

(1) #pragma gcc dependency dependency測試當前檔案(既該語句所在的程式**)與指定檔案(既#pragma語句最後列出的檔案)的時間戳. 如果指定檔案比當前檔案新, 則給出警告資訊. e.g. 在demo.c中給出這樣一句:

然後在demo.c所在的目錄新建乙個更新的檔案: to

ucht

emp−

file

,編譯:

gcc demo.c 會給出這樣的警告資訊: warning: current file is older than temp-file 如果當前檔案比指定的檔案新, 則不給出任何警告資訊.

還可以在在#pragma中給新增自定義的警告資訊. e.g.

1.c:27:38: warning: extra tokens at end of #pragma directive

1.c:27:38: warning: current file is older than temp-file

注意: 後面新增的警告資訊要用」「引用起來, 否則gcc將給出警告資訊.

(2) #pragma gcc poison token(s) 若源**中出現了#pragma中給出的token(s), 則編譯時顯示警告資訊. 它一般用於在呼叫你不想使用的函式時候給出出錯資訊. e.g.

注意, 如果呼叫了poison中給出的標記, 那麼編譯器會給出的是出錯資訊. 關於第一條警告, 我還不知道怎麼避免, 用」「將token(s)引用起來也不行.

(3) #pragma gcc system_header 從#pragma gcc system_header直到檔案結束之間的**會被編譯器視為系統標頭檔案之中的**. 系統標頭檔案中的**往往不能完全遵循c標準, 所以標頭檔案之中的警告資訊往往不顯示. (除非用 #warning顯式指明). (這條#pragma語句還沒發現用什麼大的用處)

由於#pragma不能用於巨集擴充套件, 所以gcc還提供了_pragma: e.g.

#define pragma_dep #pragma gcc dependency "temp-file" ```

由於預處理之進行一次巨集擴充套件, 採用上面的方法會在編譯時引發錯誤, 要將#pragma語句定義成乙個巨集擴充套件, 應該使用下面的_pragma語句:

注意, ()中包含的」「引用之前引該加上\轉義字元.

9, #, ##

e.g.

#define test(a,b) printf( #a

"<"

#b"=%d\n", (a)<(b)); ``

`注意: #只針對緊隨其後的token有效!

##用於將它前後的兩個token組合在一起轉換成以這兩個token為內容的字串常量. 注意##前後必須要有token. e.g.

之後呼叫: type(int, a) = 1; type(long, b) = 1999; 將被替換為: int a = 1; long b = 1999;

(10) #warning, #error

tokens中的va_args被替換為函式巨集定義中的」…」可變引數列表.

注意在使用#define時候的一些常見錯誤:

=, ; 的使用要值得注意. 再就是呼叫函式巨集是要注意, 不要多給出」;」.

C語言程式設計規範5 預編譯巨集

我們不僅要寫高效的 還要寫可讀性很強的 隨著我們所開發系統的複雜性的不斷提高,這就要求我們所寫的程式具有3個特性 1 可讀性 2 可多人協作性 3 可移植性。但是,像我們這樣電子專業畢業的學生,都沒有接受過 軟體設計方 作業系統原理 等課程的深入訓練,這就使我們所寫的程式與軟體專業工程師所寫的程式具...

C語言的預編譯

technorati 標籤 c,預編譯,巨集,檔案替換,條件編譯 由 源 到 可執行檔案 的過程包括四個步驟 預編譯 編譯 彙編 鏈結。所以,首先就應該清楚的首要問題就是 預編譯只是對程式的文字起作用,換句話說就是,預編譯階段僅僅對源 的單詞進行變換,而不是對程式中的變數 函式等。預編譯指令的基本知...

C語言的預編譯

預編譯指令基本分類如下 類別指令 預定義符號 file line date time stdc 巨集 define 檔案包含 include 條件編譯 if elif else ifdef ifndef endif 還有一些指令,名稱和功能如下表 指令功能 空指令 undef 移除乙個空定義 err...