粉絲問答
有個粉絲關于條件編譯的問題,程序一直編譯報錯。我整理了關鍵的部分,下面代碼是頭文件中的定義。
#ifdef EXTERN #undef EXTERN #define EXTERN #else #define EXTERN extern #endif EXTERN int a;
報錯的內(nèi)容就是error: unknown type name 'EXTERN,報錯的地方是EXTERN int a;
分析
乍一看條件編譯好像并沒有什么不妥,但編譯器確實已經(jīng)報錯了,那就只能說確實沒有定義?。
首先,用戶的意圖是想用宏EXTERN代替關鍵字extern。
針對此模塊,要保證EXTERN就是extern,所以需要判斷外部是否已經(jīng)定義了EXTERN。如果已經(jīng)定義了,則需要取消宏定義后再重新定義。
那這里又有同學問了,如果外部已經(jīng)定義了EXTERN,為什么還要取消宏定義再重新定義呢,直接用不可以嗎?
嚴格來說是不行的,假設外部有個地方定義了
#define EXTERN const
那么此時EXTERN就不再是extern了,意義完全變了。這時候又有同學說了,怎么可能會有人把EXTERN定義成const呢,我只能說,我也希望不會出現(xiàn)這種情況吧...
如果外部沒有定義EXTERN會進入else分支,則在本模塊直接定義。
看起來都是這么合情合理。
查看預編譯文件
上面已經(jīng)分析了一次,邏輯上好像沒問題(指出問題了我還這么繼續(xù)寫下文)。既然分析沒有問題,那我們直接去看預處理文件吧,簡單寫個Demo,頭文件不變。
gcc生成預編譯命令為gcc -E .\main.c -o main.i參數(shù)E代表預編譯處理,o代表輸出,后面跟一個文件名。代表將源文件預編譯處理將處理的結果輸出到main.i文件中。
內(nèi)部定義EXTERN
假設我們在源文件包含頭文件之前已經(jīng)定義了EXTERN,如下:
#include#define EXTERN extern #include"main.h"
然后對源文件預編譯處理并截取關鍵信息:
# 10 ".\\main.h" int a; # 4 ".\\main.c" 2
未定義EXTERN
源文件部分代碼,此時沒有定義EXTERN。
#include#include"main.h"
同樣對源文件預編譯處理并截取關鍵信息:
# 10 ".\\main.h" extern int a; # 4 ".\\main.c" 2
對比
當外部定義了EXTERN時,頭文件預編譯的結果沒有對變量a做extern聲明。外部定義了EXTERN時,頭文件預編譯的結果對變量a做了extern聲明。
結果
宏的本質(zhì)是代碼替換,上述對比表明,當外部定義了EXTERN時,在處理EXTERN int a;前EXTERN變成了一個空宏。
那我們再回頭看看頭文件中的條件編譯,如果外部定義了EXTERN則取消宏定義,并重新定義EXTERN,但是在重新定義宏的時候,這里僅僅是定義了EXTERN。并沒有指明EXTERN是extern。所以編譯總是提示unknown type name 'EXTERN
問題2-宏的處理順序
問題已經(jīng)找出來了,但是粉絲現(xiàn)在又有了新的疑問,同一個宏在多個文件是如何處理的?
其實上面的兩種測試代碼已經(jīng)能夠表明了,因為預編譯也是按照先后順序依次處理的,所以宏的處理過程也是按照先后順序。這也是我為什么在包含main頭文件之前定義EXTERN,而不是在包含頭文件之后定義EXTERN。
延伸問題-宏判斷
發(fā)現(xiàn)有些同學對于一些宏的判斷有些分不清楚,不清楚應該在何種場合使用。在此仍然以EXTERN為例吧。
第一種
#define EXTERN
依稀記得當時剛畢業(yè)出來工作,當我第一次看到代碼有這種定義的時候,也是挺懵逼的。甚至懷疑是不是寫錯了?因為我當時認為后面少了數(shù)字。為什么是少數(shù)字呢,因為在我的印象中宏都是下面這種使用方法。
#define VALUE (100)
第一種方式宏定義僅僅代表定義了這個標識符,而不用關心它具體是什么。
常用的就是在調(diào)試模式下定義DEBUG,發(fā)布程序的時候?qū)EBUG關閉。主要是用來打印一些信息,方便程序員調(diào)試用的,如下:
#ifdef DEBUG //打印信息 #endif
第二種
#if EXTERN
注意這種使用方法,是一個判斷語句,跟我們編程用if判斷邏輯相同,也就是EXTERN不為0才能成立。
這種用法通常都是在定義宏時直接定義成1,例如:
#define EXTERN (1)
第三種
#ifdef EXTERN
這種方式和第二種有區(qū)別,這種判斷只關注有沒有定義,但凡你定義了,不管是什么牛馬蛇神,條件都是成立的。
最后
關于宏相關的知識點,之前寫過一篇文章。有興趣的可以看看。
C語言中宏定義的盲區(qū)
這篇文章主要也是宏相關的,主要是實際編程中的問題。條件編譯報錯,可以去查看預處理文件,反向分析。如果你對C理解得比較深,可能一眼就能看出問題所在了。
每個人都是從小白過來的,需要時間慢慢沉淀,慢慢也就好了,加油~