2011-09-29 22 views
5

在學習C之前,我遇到了#define預處理指令,然後在讀取的一些代碼中遇到了它。但除了使用它來定義常量替換和宏定義之外,我沒有真正地忽視它沒有使用「body」或標記字符串的特殊情況。什麼用例需要#define而沒有令牌字符串?

就拿這條線:

#define OCSTR(X) 

就這樣!有什麼可以使用這個或更好的,什麼時候使用#define是必要的?

+0

這可以與相互結合是有用的允許條件編譯的一組指令。沒有標記字符串的#define從源文件中刪除標識符的出現。標識符保持定義,可以使用#if定義和#ifdef指令進行測試。 – AminM

回答

6

這是在兩種情況下使用。第一個也是最常見的涉及 條件編譯:

#ifndef XYZ 
#define XYZ 
// ... 
#endif 

你一定用這個自己爲包括後衛,但它也可以用於諸如系統的依賴 :

#ifdef WIN32 
// Windows specific code here... 
#endif 

(在這種情況下,WIN32更可能在命令行上定義,但 也可以在"config.hpp"文件中定義。)這通常會涉及類似對象的宏(不帶參數列表或圓括號的 ) 。

第二個是條件編譯的結果。東西 這樣的:

#ifdef DEBUG 
#define TEST(X) text(X) 
#else 
#define TEST(X) 
#endif 

這使得寫作一樣東西:

TEST(X); 

將調用的函數,如果DEBUG定義,什麼事都不做,如果它 並非如此。

+0

接受這並不是因爲別人不正確,而是因爲它增加了對正確答案的更多解釋。謝謝 – nemesisfixx

3

這種宏通常出現在一對和內部條件#ifdef爲:

#ifdef _DEBUG 
    #define OCSTR(X) 
#else 
    #define OCSTR(X) SOME_TOKENS_HERE 
#endif 

又如,

#ifdef __cplusplus 
    #define NAMESPACE_BEGIN(X) namespace X { 
    #define NAMESPACE_END } 
#else 
    #define NAMESPACE_BEGIN(X) 
    #define NAMESPACE_END 
#endif 
0

這可以用於當你可能想無聲一些功能。例如,在調試模式要打印一些調試語句,並在生產代碼要忽略它們:

#ifdef DEBUG 
#define PRINT(X) printf("%s", X) 
#else 
#define PRINT(X) // <----- silently removed 
#endif 

用法:

void foo() 
{ 
    PRINT("foo() starts\n"); 
    ... 
} 
+0

你的回答(和許多其他人)是真的,但你的榜樣是危險的。如果在PRINT(X)之前存在沒有包含{}的if()會怎麼樣?對讀者來說:要小心,這只是一個不被原樣使用的簡單例子。 – Offirmo

+0

這就是爲什麼在C/C++中,每個宏應該是一個表達式,只是爲了避免這種情況。問候。 – BigMike

0

#define宏簡單地更換,從字面上看,通過替換文本在預處理期間。如果沒有替換文本,那麼......它們被替換爲沒有!所以這個源代碼:

#define FOO(x) 

print(FOO(hello world)); 

將預處理逼到這樣的:

print(); 

這可能是有用擺脫你不想要的東西,比如,說,assert()。它主要用於有條件的情況,但在某些情況下,存在非空的身體。

0

正如您在上面的回覆中看到的那樣,它在調試代碼時非常有用。

#ifdef DEBUG 
#define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr) 
#else 
#define debug(msg) 
#endif 

因此,當您在調試時,該函數將打印行號和文件名,以便您知道是否有錯誤。如果你沒有調試,它只會產生沒有輸出

0

這樣的事情有很多用途。

例如,一個是讓宏在不同的版本中有不同的行爲。例如,如果你想調試消息,你可以有這樣的事情:

#ifdef _DEBUG 
    #define DEBUG_LOG(X, ...) however_you_want_to_print_it 
#else 
    #define DEBUG_LOG(X, ...) // nothing 
#endif 

另一個用途是根據您的系統上你的頭文件來定製。這是從我的檯面實現OpenGL頭在Linux中:

#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__)) 
# if defined(__MINGW32__) && defined(GL_NO_STDCALL) || defined(UNDER_CE) /* The generated DLLs by MingW with STDCALL are not compatible with the ones done by Microsoft's compilers */ 
# define GLAPIENTRY 
# else 
# define GLAPIENTRY __stdcall 
# endif 
#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */ 
# define GLAPIENTRY __stdcall 
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 
# define GLAPIENTRY 
#endif /* WIN32 && !CYGWIN */ 

#ifndef GLAPIENTRY 
#define GLAPIENTRY 
#endif 

而且在頭部聲明中使用,如:

GLAPI void GLAPIENTRY glClearIndex(GLfloat c); 

GLAPI void GLAPIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); 

GLAPI void GLAPIENTRY glClear(GLbitfield mask); 

... 

(我刪除了GLAPI的部分)

所以你得到的圖片,在某些情況下使用並且在其他情況下不使用的宏可以被定義爲關於這些情況的東西,而不是那些其他情況。

其他情況可能如下:

如果宏不帶參數,它可能只是宣佈了一些情況。一個着名的例子是保護頭文件。另一個例子是這樣的

#define USING_SOME_LIB 

,後來也像這樣被使用:

#ifdef USING_SOME_LIB 
... 
#else 
... 
#endif 

可能是因爲宏在某個階段用來做一些事情(例如日誌),但隨後在發佈時,所有者決定日誌不再有用,並簡單地刪除宏的內容,使其變爲空。儘管如此,我並不推薦使用我在答案一開始提到的方法。

最後,也可能是存在只是爲了更多的解釋,例如,你可以說

#define DONT_CALL_IF_LIB_NOT_INITIALIZED 

,你寫這樣的功能:

void init(void); 
void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED; 

雖然這最後一種情況是有點荒唐,但它會在這種情況下是有道理的:

#define IN 
#define OUT 

void function(IN char *a, OUT char *b); 
2

一個奇怪的情況下,我最近挖出來回答questi原來只是簡單的評論性質。有問題的代碼看起來像:

void CLASS functionName(){ 
    // 
    // 
    // 
} 

我發現這只是一個空#define,這是作者選擇了記錄的功能項目訪問的全局變量:

C++ syntax: void CLASS functionName()?

所以與/* CLASS */沒有什麼不同,除了不允許像/* CLAAS */這樣的拼寫錯誤...其他一些小好處也許(?)

0

我同意每一個答案,但我想指出一個小小的事情。

是C純粹的我已經長大了這樣的斷言:每#define應該是一種表達,所以,即使是使用常見的做法:

#define WHATEVER 

#ifdef WHATEVER 
測試

我認爲它總是更好的寫作:

#define WHATEVER (1) 

#debug宏應表述:

#define DEBUG (xxx) (whatever you want for debugging, value) 

這樣,你是從#macros濫用完全安全,並防止討厭的問題(特別是在1000萬C線項目)

+0

這個'#if'和'#ifdef'的辯論可能會讓你感興趣,我個人傾向'#if'一邊http://stackoverflow.com/questions/135069/ifdef-vs-if-which-is-更安全 – HostileFork

+0

想到#if 0的有效用法,用於評論整段代碼:D。順便說一句,這很有趣。像往常一樣,沒有正確或錯誤的做事方式,這取決於你在做什麼。我會盡快給它閱讀。謝謝。 – BigMike