2015-09-04 211 views
89

所有在我們的C代碼的基礎上,我看到每一個宏定義方式如下:爲什麼只定義一個宏,如果它尚未定義?

#ifndef BEEPTRIM_PITCH_RATE_DEGPS 
#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#endif 

#ifndef BEEPTRIM_ROLL_RATE_DEGPS 
#define BEEPTRIM_ROLL_RATE_DEGPS     0.2f 
#endif 

#ifndef FORCETRIMRELEASE_HOLD_TIME_MS 
#define FORCETRIMRELEASE_HOLD_TIME_MS    1000.0f 
#endif 

#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS  50.0f 
#endif 

什麼是做這些定義的檢查,而不是僅僅定義宏的原理是什麼?

#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#define BEEPTRIM_ROLL_RATE_DEGPS     0.2f 
#define FORCETRIMRELEASE_HOLD_TIME_MS    1000.0f 
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS  50.0f 

我無法在網絡上的任何地方找到這種做法。

+6

在代碼中的其他位置更改常量可以保證以這種方式工作。如果別的地方有人定義了這些宏之一,那麼在解析該文件時,它們不會被預處理器覆蓋。 –

+8

這是WET設計原理的一個例子。 – stark

+0

用一個示例發佈答案,嘗試編譯它。 –

回答

132

這使您可以覆蓋宏當你編譯:

gcc -DMACRONAME=value 

在頭文件的定義作爲默認值。

17

我不知道上下文,但是這可以用來爲用戶提供覆蓋由這些宏定義設置的值的可用性。如果用戶爲這些宏中的任何一個顯式定義了一個不同的值,它將被用來代替這裏使用的值。

例如,在g ++中,您可以在編譯過程中使用-D標誌將值傳遞給宏。

14

這樣做是爲了使頭文件的用戶可以覆蓋來自他/她的代碼或編譯器的-D標誌的定義。

7

任何C項目駐留在多個源文件。在處理單個源文件時,檢查似乎(實際上)沒有意義,但是在處理大型C項目時,最好在定義常量之前檢查現有的定義。這個想法很簡單:您需要該特定源文件中的常量,但它可能已經在另一個文件中定義。

51

正如我在評論說,想象一下這種情況:

foo.h中

#define FOO 4 

的defs.h

#ifndef FOO 
#define FOO 6 
#endif 

#ifndef BAR 
#define BAR 4 
#endif 

bar.c

#include "foo.h" 
#include "defs.h" 

#include <stdio.h> 

int main(void) 
{ 
    printf("%d%d", FOO, BAR); 
    return 0; 
} 

將打印44

但是,如果條件ifndef不存在,則結果將是MACRO重新定義的編譯警告,它將打印64

$ gcc -o bar bar.c 
In file included from bar.c:2:0: 
defs.h:1:0: warning: "FOO" redefined [enabled by default] 
#define FOO 6 
^ 
In file included from bar.c:1:0: 
foo.h:1:0: note: this is the location of the previous definition 
#define FOO 4 
^ 
+1

這是特定於編譯器的。重新定義一個類似宏的宏是非法的,除非重定義是「相同的」(這裏有更多的技術規範,但這裏並不重要)。非法代碼需要診斷,並且在發佈診斷(此處爲警告)時,編譯器可以自由地執行任何操作,包括編譯具有特定於實現的結果的代碼。 –

+7

如果你對同一個宏有矛盾的定義,你會不會*在大多數情況下得到警告?而不是默默使用第一個定義(因爲第二個定義使用'ifdef'來避免重新定義)。 –

+0

@PeterCordes大多數時候,'#infdef's下的定義被用作「後備」或「默認」值。基本上,「如果用戶配置了它,好吧,如果沒有,我們使用默認值。」 – Angew

2

你能想到的框架/庫,讓用戶默認預設,允許用戶編寫並在其上工作。 這些定義在不同的文件中被傳播,並且最終用戶被建議包含它的config.h文件,他可以在其中配置它的值。 如果用戶忘記了一些定義,系統可以繼續工作,因爲預設。

1

使用

#ifndef BEEPTRIM_PITCH_RATE_DEGPS 
#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#endif 

允許用戶定義使用命令行參數的宏值(在gcc /鐺/ VS)-DBEEPTRIM_PITCH_RATE_DEGPS=0.3f

還有另外一個重要原因。以不同方式重新定義預處理器宏是錯誤的。見this answer to another SO question。如果沒有進行#ifndef檢查,編譯器應在編譯器調用中使用-DBEEPTRIM_PITCH_RATE_DEGPS=0.3f作爲命令行參數時產生錯誤。