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