在學習C之前,我遇到了#define
預處理指令,然後在讀取的一些代碼中遇到了它。但除了使用它來定義常量替換和宏定義之外,我沒有真正地忽視它沒有使用「body」或標記字符串的特殊情況。什麼用例需要#define而沒有令牌字符串?
就拿這條線:
#define OCSTR(X)
就這樣!有什麼可以使用這個或更好的,什麼時候使用#define
是必要的?
在學習C之前,我遇到了#define
預處理指令,然後在讀取的一些代碼中遇到了它。但除了使用它來定義常量替換和宏定義之外,我沒有真正地忽視它沒有使用「body」或標記字符串的特殊情況。什麼用例需要#define而沒有令牌字符串?
就拿這條線:
#define OCSTR(X)
就這樣!有什麼可以使用這個或更好的,什麼時候使用#define
是必要的?
這是在兩種情況下使用。第一個也是最常見的涉及 條件編譯:
#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
定義,什麼事都不做,如果它 並非如此。
接受這並不是因爲別人不正確,而是因爲它增加了對正確答案的更多解釋。謝謝 – nemesisfixx
這種宏通常出現在一對和內部條件#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
這可以用於當你可能想無聲一些功能。例如,在調試模式要打印一些調試語句,並在生產代碼要忽略它們:
#ifdef DEBUG
#define PRINT(X) printf("%s", X)
#else
#define PRINT(X) // <----- silently removed
#endif
用法:
void foo()
{
PRINT("foo() starts\n");
...
}
#define
宏簡單地更換,從字面上看,通過替換文本在預處理期間。如果沒有替換文本,那麼......它們被替換爲沒有!所以這個源代碼:
#define FOO(x)
print(FOO(hello world));
將預處理逼到這樣的:
print();
這可能是有用擺脫你不想要的東西,比如,說,assert()
。它主要用於有條件的情況,但在某些情況下,存在非空的身體。
正如您在上面的回覆中看到的那樣,它在調試代碼時非常有用。
#ifdef DEBUG
#define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr)
#else
#define debug(msg)
#endif
因此,當您在調試時,該函數將打印行號和文件名,以便您知道是否有錯誤。如果你沒有調試,它只會產生沒有輸出
這樣的事情有很多用途。
例如,一個是讓宏在不同的版本中有不同的行爲。例如,如果你想調試消息,你可以有這樣的事情:
#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);
一個奇怪的情況下,我最近挖出來回答questi原來只是簡單的評論性質。有問題的代碼看起來像:
void CLASS functionName(){
//
//
//
}
我發現這只是一個空#define
,這是作者選擇了記錄的功能項目訪問的全局變量:
C++ syntax: void CLASS functionName()?
所以與/* CLASS */
沒有什麼不同,除了不允許像/* CLAAS */
這樣的拼寫錯誤...其他一些小好處也許(?)
我同意每一個答案,但我想指出一個小小的事情。
是C純粹的我已經長大了這樣的斷言:每#define
應該是一種表達,所以,即使是使用常見的做法:
#define WHATEVER
與
#ifdef WHATEVER
測試
我認爲它總是更好的寫作:
#define WHATEVER (1)
也#debug
宏應表述:
#define DEBUG (xxx) (whatever you want for debugging, value)
這樣,你是從#macros
濫用完全安全,並防止討厭的問題(特別是在1000萬C線項目)
這個'#if'和'#ifdef'的辯論可能會讓你感興趣,我個人傾向'#if'一邊http://stackoverflow.com/questions/135069/ifdef-vs-if-which-is-更安全 – HostileFork
想到#if 0的有效用法,用於評論整段代碼:D。順便說一句,這很有趣。像往常一樣,沒有正確或錯誤的做事方式,這取決於你在做什麼。我會盡快給它閱讀。謝謝。 – BigMike
這可以與相互結合是有用的允許條件編譯的一組指令。沒有標記字符串的#define從源文件中刪除標識符的出現。標識符保持定義,可以使用#if定義和#ifdef指令進行測試。 – AminM