ifndef?
ifndef, #define, #endif 作用
ifndef
它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种----条件编译。 在c语言中,对同一个变量或者函数进行多次声明是不会报错的。所以如果h文件里只是进行了声明工作,即使不使用# ifndef宏定义,多个c文件包含同一个h文件也不会报错。
但是在c++语言中,#ifdef的作用域只是在单个文件中。所以如果h文件里定义了全局变量,即使采用#ifdef宏定义,多个c文件包含同一个h文件还是会出现全局变量重定义的错误。 使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错误。 示例:
ifndef x //先测试x是否被宏定义过
define x
程序段1blabla~ //如果x没有被宏定义过,定义x,并编译程序段 1
endif
程序段2blabla~ //如果x已经定义过了则编译程序段2的语句,“忽视”程序段 1 条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。了解:条件编译当然也可以用条件语句来实现。 但是用条件语句将会对整个源程序进行编译,生成的目标程序程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生成的目标程序较短。如果条件选择的程序段很长,采用条件编译的方法是十分必要的。
ifndef 和 #endif 要一起使用,如果丢失#endif,可能会报错。总结一下:在c语言中,对同一个变量或者函数进行多次声明是不会报错的。所以如果h文件里只是进行了声明工作,即使不使用# ifndef宏定义,一个c文件多次包含同一个h文件也不会报错。 使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错.
ifdef
与ifndef类似,ifdef顾名思义,就是if define,看例子
ifdef x
程序1blabla~
endif
翻译:如果宏定义了x,则执行程序1.
此外,还有其他形式,还是看例子好些:
ifndef x
define x
程序段 1
else
程序段 2
endif
当x没有由#define定义过,则编译“程序段1”,否则编译“程序段2”。
if 表达式
程序段 1
else
程序段 2
endif
它的作用是 当“表达式”值为真时。编译程序段1。否则则编译程序段2。当没有程序段2时,直接是#if---#endif
define
在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。“define”为宏定义命令。
被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。
优点:
(1) 方便程序的修改。这个就不多说了。
(2) 提高程序的运行效率。使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义 http://www.cnblogs.com/challenger-vip/p/3386819.html
頭件的中的#ifndef,這是一個很關鍵的東西。比如你有兩個C文件,這兩個C文件都include了同一個頭文件。而編譯時,這兩個C文件要一同編譯成一個可運行文件,於是問題來了,大量的聲明衝突。
還是把頭文件的內容都放在#ifndef和#endif中吧。不管你的頭文件會不會被多個文件引用,你都要加上這個。一般格式是這樣的:
ifndef <標識>
define <標識>
...... ......
endif
<標識>在理論上來說可以是自由命名的,但每個頭文件的這個「標識」都應該是唯一的。標識的命名規則一般是頭文件名全大寫,前後加下劃線,並把文件名中的「.」也變成下劃線,如:stdio.h
ifndef STDIO_H
define STDIO_H
......
endif
2.在#ifndef中定義變量出現的問題(一般不定義在#ifndef中)。
ifndef AAA
define AAA
... int i; ...
endif
裡面有一個變量定義 在vc中鏈接時就出現了i重複定義的錯誤,而在c中成功編譯。
結論:
(1).當你第一個使用這個頭的.cpp文件生成.obj的時候,int i 在裡面定義了當另外一個使用這個的.cpp再次[單獨]生成.obj的時候,int i 又被定義然後兩個obj被另外一個.cpp也include 這個頭的,連接在一起,就會出現重複定義.
(2).把源程序文件擴展名改成.c後,VC按照C語言的語法對源程序進行編譯,而不是C++。在C語言中,若是遇到多個int i,則自動認為其中一個是定義,其他的是聲明。
(3).C語言和C++語言連接結果不同,可能(猜測)時在進行編譯的時候,C++語言將全局 變量默認為強符號,所以連接出錯。C語言則依照是否初始化進行強弱的判斷的。(參考)
解決方法:
(1).把源程序文件擴展名改成.c。
(2).推薦解決方案: .h中只聲明 extern int i;在.cpp中定義
ifndef X_H
define X_H
extern int i;
endif //X_H
注意問題:
(1).變量一般不要定義在.h文件中。
一般情況下,源程序中所有的行都參加編譯。但是有時希望對其中一部分內容只在滿足一定條件才進行編譯,也就是對一部分內容指定編譯的條件,這就是「條件編譯」。有時,希望當滿足某條件時對一組語句進行編譯,而當條件不滿足時則編譯另一組語句。 條件編譯命令最常見的形式為:
#ifdef 標識符
程序段1
#else
程序段2
#endif
它的作用是:當標識符已經被定義過(一般是用#define命令定義),則對程序段1進行編譯,否則編譯程序段2。
其中#else部分也可以沒有,即:
#ifdef
程序段1
#denif
這裡的「程序段」可以是語句組,也可以是命令行。這種條件編譯可以提高C源程序的通用性。如果一個C源程序在不同計算機系統上系統上運行,而不同的計算機 又有一定的差異。例如,我們有一個數據類型,在Windows平台中,應該使用long類型表示,而在其他平台應該使用float表示,這樣往往需要對源 程序作必要的修改,這就降低了程序的通用性。可以用以下的條件編譯:
#ifdef WINDOWS
#define MYTYPE long
#else
#define MYTYPE float
#endif
如果在Windows上編譯程序,則可以在程序的開始加上
#define WINDOWS
這樣則編譯下面的命令行:
#define MYTYPE long
如果在這組條件編譯命令之前曾出現以下命令行:
#define WINDOWS 0
則預編譯後程序中的MYTYPE都用float代替。這樣,源程序可以不必作任何修改就可以用於不同類型的計算機系統。當然以上介紹的只是一種簡單的情況,可以根據此思路設計出其它的條件編譯。
例如,在調試程序時,常常希望輸出一些所需的信息,而在調試完成後不再輸出這些信息。可以在源程序中插入以下的條件編譯段:
#ifdef DEBUG
print ("device_open(%p) ", file);
#endif
如果在它的前面有以下命令行:
#define DEBUG
則在程序運行時輸出file指針的值,以便調試分析。調試完成後只需將這個define命令行刪除即可。有人可能覺得不用條件編譯也可達此目的,即在調試 時加一批printf語句,調試後一一將printf語句刪除去。的確,這是可以的。但是,當調試時加的printf語句比較多時,修改的工作量是很大 的。用條件編譯,則不必一一刪改printf語句,只需刪除前面的一條「#define DEBUG」命令即可,這時所有的用DEBUG作標識符的條件編譯段都使其中的printf語句不起作用,即起統一控制的作用,如同一個「開關」一樣。
有時也採用下面的形式:
#ifndef 標識符
程序段1
#else
程序段2
#endif
只是第一行與第一種形式不同:將「ifdef」改為「ifndef」。它的作用是:若標識符未被定義則編譯程序段1,否則編譯程序段2。這種形式與第一種形式的作用相反。
以上兩種形式用法差不多,根據需要任選一種,視方便而定。
還有一種形式,就是#if後面的是一個表達式,而不是一個簡單的標識符:
#if 表達式
程序段1
#else
程序段2
#endif
它的作用是:當指定的表達式值為真(非零)時就編譯程序段1,否則編譯程序段2。可以事先給定一定條件,使程序在不同的條件下執行不同的功能。
作用範圍就是當前文件啊。因為編譯是以cpp或c文件位單位的嘛。還以這個為例:
//正常代碼
ifdef _DEBUG
TRACE("Some infomation");
else
//Now is release version,so do nothing
endif
//正常代碼
編譯時是先把所有的預編譯處理展開(比如宏)再編譯,所以Debug模式下,編譯時的代碼是: //正常代碼 TRACE("Some infomation"); //正常代碼
Release模式下的代碼是: //正常代碼 //正常代碼