C++內(nèi)存分配及管理--精選文檔_第1頁
C++內(nèi)存分配及管理--精選文檔_第2頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、在C+中,內(nèi)存分成5個區(qū),他們分別是堆、棧、自由存儲區(qū)、全局/靜態(tài)存儲區(qū)和常量存儲區(qū)。棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變量的存儲區(qū)。里面的變量通常是局部變量、函數(shù)參數(shù)等。堆,就是那些由new分配的內(nèi)存塊,他們的釋放編譯器不去管,由我們的應(yīng)用程序去控制,一般一個new就要對應(yīng)一個delete。如果程序員沒有釋放掉,那么在程序結(jié)束后,操作系統(tǒng)會自動回收。自由存儲區(qū),就是那些由malloc等分配的內(nèi)存塊,他和堆是十分相似的,不過它是用free來結(jié)束自己的生命的。全局/靜態(tài)存儲區(qū),全局變量和靜態(tài)變量被分配到同一塊內(nèi)存中,在以前的C語言中,全局變量又分為初始化的和未初始化的

2、,在C+里面沒有這個區(qū)分了,他們共同占用同一塊內(nèi)存區(qū)。常量存儲區(qū),這是一塊比較特殊的存儲區(qū),他們里面存放的是常量,不允許修改(當(dāng)然,你要通過非正當(dāng)手段也可以修改,而且方法很多,在const的思考一文中,我給出了6種方法)明確區(qū)分堆與棧在bbs上,堆與棧的區(qū)分問題,似乎是一個永恒的話題,由此可見,初學(xué)者對此往往是混淆不清的,所以我決定拿他第一個開刀。首先,我們舉一個例子:void f() int* p=new int5; 這條短短的一句話就包含了堆與棧,看到new,我們首先就應(yīng)該想到,我們分配了一塊堆內(nèi)存,那么指針p呢?他分配的是一塊棧內(nèi)存,所以這句話的意思就是:在棧內(nèi)存中存放了一個指向一塊堆內(nèi)

3、存的指針p。在程序會先確定在堆中分配內(nèi)存的大小,然后調(diào)用operator new分配內(nèi)存,然后返回這塊內(nèi)存的首地址,放入棧中,他在VC6下的匯編代碼如下:00401028 push 14h0040102A call operator new (00401060)0040102F add esp,400401032 mov dword ptr ebp-8,eax00401035 mov eax,dword ptr ebp-800401038 mov dword ptr ebp-4,eax這里,我們?yōu)榱撕唵尾]有釋放內(nèi)存,那么該怎么去釋放呢?是delete p么?澳,錯了,應(yīng)該是delete p,

4、這是為了告訴編譯器:我刪除的是一個數(shù)組,VC6就會根據(jù)相應(yīng)的Cookie信息去進(jìn)行釋放內(nèi)存的工作。好了,我們回到我們的主題:堆和棧究竟有什么區(qū)別?主要的區(qū)別由以下幾點(diǎn):1、管理方式不同;2、空間大小不同;3、能否產(chǎn)生碎片不同;4、生長方向不同;5、分配方式不同;6、分配效率不同;管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。空間大?。阂话銇碇v在32位系統(tǒng)下,堆內(nèi)存可以達(dá)到4G的空間,從這個角度來看堆內(nèi)存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小的,例如,在VC6下面,默認(rèn)的??臻g大小是1M(好像

5、是,記不清楚了)。當(dāng)然,我們可以修改:打開工程,依次操作菜單如下:Project-Setting-Link,在Category 中選中Output,然后在Reserve中設(shè)定堆棧的最大值和commit。注意:reserve最小值為4Byte;commit是保留在虛擬內(nèi)存的頁文件里面,它設(shè)置的較大會使棧開辟較大的值,可能增加內(nèi)存的開銷和啟動時間。碎片問題:對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列,他們是如此的一一對應(yīng),以至于永遠(yuǎn)都不可能有一個內(nèi)存塊從棧中間彈出,在他彈出之前,在他上

6、面的后進(jìn)的棧內(nèi)容已經(jīng)被彈出,詳細(xì)的可以參考數(shù)據(jù)結(jié)構(gòu),這里我們就不再一一討論了。生長方向:對于堆來講,生長方向是向上的,也就是向著內(nèi)存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內(nèi)存地址減小的方向增長。分配方式:堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實(shí)現(xiàn)。分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比

7、較高。堆則是C/C+函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu)/操作系統(tǒng))在堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會分到足夠大小的內(nèi)存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。從這里我們可以看到,堆和棧相比,由于大量new/delete的使用,容易造成大量的內(nèi)存碎片;由于沒有專門的系統(tǒng)支持,效率很低;由于可能引發(fā)用戶態(tài)和核心態(tài)的切換,內(nèi)存的申請,代價變得更加昂貴。所以棧在程序中是應(yīng)用最廣泛的,就算是函數(shù)的調(diào)用也利用棧去完成,函

8、數(shù)調(diào)用過程中的參數(shù),返回地址,EBP和局部變量都采用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。雖然棧有如此眾多的好處,但是由于和堆相比不是那么靈活,有時候分配大量的內(nèi)存空間,還是用堆好一些。無論是堆還是棧,都要防止越界現(xiàn)象的發(fā)生(除非你是故意使其越界),因?yàn)樵浇绲慕Y(jié)果要么是程序崩潰,要么是摧毀程序的堆、棧結(jié)構(gòu),產(chǎn)生以想不到的結(jié)果,就算是在你的程序運(yùn)行過程中,沒有發(fā)生上面的問題,你還是要小心,說不定什么時候就崩掉,那時候debug可是相當(dāng)困難的:)1、什么是const? 常類型是指使用類型修飾符const說明的類型,常類型的變量或?qū)ο蟮闹凳遣荒鼙桓碌?。(?dāng)然,我們可以偷梁換柱進(jìn)行更

9、新:)2、為什么引入const? const 推出的初始目的,正是為了取代預(yù)編譯指令,消除它的缺點(diǎn),同時繼承它的優(yōu)點(diǎn)。3、cons有什么主要的作用? (1)可以定義const常量,具有不可變性。 例如: const int Max=100; int ArrayMax; (2)便于進(jìn)行類型檢查,使編譯器對處理內(nèi)容有更多了解,消除了一些隱患。例如: void f(const int i) . 編譯器就會知道i是一個常量,不允許修改; (3)可以避免意義模糊的數(shù)字出現(xiàn),同樣可以很方便地進(jìn)行參數(shù)的調(diào)整和修改。 同宏定義一樣,可以做到不變則已,一變都變!如(1)中,如果想修改Max的內(nèi)容,只需要:con

10、st int Max=you want;即可! (4)可以保護(hù)被修飾的東西,防止意外的修改,增強(qiáng)程序的健壯性。 還是上面的例子,如果在函數(shù)體內(nèi)修改了i,編譯器就會報錯; 例如: void f(const int i) i=10;/error! (5) 為函數(shù)重載提供了一個參考。 class A . void f(int i) .file:/一個函數(shù) void f(int i) const .file:/上一個函數(shù)的重載 . ; (6) 可以節(jié)省空間,避免不必要的內(nèi)存分配。 例如: #define PI 3.14159file:/常量宏 const doulbe Pi=3.14159;file:

11、/此時并未將Pi放入ROM中 . double i=Pi;file:/此時為Pi分配內(nèi)存,以后不再分配! double I=PI;file:/編譯期間進(jìn)行宏替換,分配內(nèi)存 double j=Pi;file:/沒有內(nèi)存分配 double J=PI;file:/再進(jìn)行宏替換,又一次分配內(nèi)存! const定義常量從匯編的角度來看,只是給出了對應(yīng)的內(nèi)存地址,而不是象#define一樣給出的是立即數(shù),所以,const定義的常量在程序運(yùn)行過程中只有一份拷貝,而#define定義的常量在內(nèi)存中有若干個拷貝。 (7) 提高了效率。 編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得

12、它成為一個編譯期間的常量,沒有了存儲與讀內(nèi)存的操作,使得它的效率也很高。3、如何使用const? (1)修飾一般常量 一般常量是指簡單類型的常量。這種常量在定義時,修飾符const可以用在類型說明符前,也可以用在類型說明符后。 例如: int const x=2;或const int x=2; (2)修飾常數(shù)組 定義或說明一個常數(shù)組可采用如下格式: int const a5=1, 2, 3, 4, 5; const int a5=1, 2, 3, 4, 5; (3)修飾常對象 常對象是指對象常量,定義格式如下: class A; const A a; A const a; 定義常對象時,同樣要

13、進(jìn)行初始化,并且該對象不能再被更新,修飾符const可以放在類名后面,也可以放在類名前面。 (4)修飾常指針 const int *A;file:/const修飾指向的對象,A可變,A指向的對象不可變 int const *A; file:/const修飾指向的對象,A可變,A指向的對象不可變 int *const A; file:/const修飾指針A, A不可變,A指向的對象可變 const int *const A;file:/指針A和A指向的對象都不可變 (5)修飾常引用 使用const修飾符也可以說明引用,被說明的引用為常引用,該引用所引用的對象不能被更新。其定義格式如下: cons

14、t double & v; (6)修飾函數(shù)的常參數(shù) const修飾符也可以修飾函數(shù)的傳遞參數(shù),格式如下: void Fun(const int Var); 告訴編譯器Var在函數(shù)體中的無法改變,從而防止了使用者的一些無意的或錯誤的修改。 (7)修飾函數(shù)的返回值: const修飾符也可以修飾函數(shù)的返回值,是返回值不可被改變,格式如下: const int Fun1(); const MyClass Fun2(); (8)修飾類的成員函數(shù): const修飾符也可以修飾類的成員函數(shù),格式如下: class ClassName public: int Fun() const; . ; 這樣,在調(diào)用函數(shù)

15、Fun時就不能修改類里面的數(shù)據(jù) (9)在另一連接文件中引用const常量 extern const int i;file:/正確的引用 extern const int j=10;file:/錯誤!常量不可以被再次賦值 另外,還要注意,常量必須初始化! 例如: const int i=5;4、幾點(diǎn)值得討論的地方: (1)const究竟意味著什么? 說了這么多,你認(rèn)為const意味著什么?一種修飾符?接口抽象?一種新類型? 也許都是,在Stroustup最初引入這個關(guān)鍵字時,只是為對象放入ROM做出了一種可能,對于const對象,C+既允許對其進(jìn)行靜態(tài)初始化,也允許對他進(jìn)行動態(tài)初始化。理想的co

16、nst對象應(yīng)該在其構(gòu)造函數(shù)完成之前都是可寫的,在析夠函數(shù)執(zhí)行開始后也都是可寫的,換句話說,const對象具有從構(gòu)造函數(shù)完成到析夠函數(shù)執(zhí)行之前的不變性,如果違反了這條規(guī)則,結(jié)果都是未定義的!雖然我們把const放入ROM中,但這并不能夠保證const的任何形式的墮落,我們后面會給出具體的辦法。無論const對象被放入ROM中,還是通過存儲保護(hù)機(jī)制加以保護(hù),都只能保證,對于用戶而言這個對象沒有改變。換句話說,廢料收集器(我們以后會詳細(xì)討論,這就一筆帶過)或數(shù)據(jù)庫系統(tǒng)對一個const的修改怎沒有任何問題。 (2)位元const V.S. 抽象const? 對于關(guān)鍵字const的解釋有好幾種方式,最常

17、見的就是位元const 和 抽象const。下面我們看一個例子: class A public: . A f(const A& a); . ; 如果采用抽象const進(jìn)行解釋,那就是f函數(shù)不會去改變所引用對象的抽象值,如果采用位元const進(jìn)行解釋,那就成了f函數(shù)不會去改變所引用對象的任何位元。 我們可以看到位元解釋正是c+對const問題的定義,const成員函數(shù)不被允許修改它所在對象的任何一個數(shù)據(jù)成員。 為什么這樣呢?因?yàn)槭褂梦辉猚onst有2個好處: 最大的好處是可以很容易地檢測到違反位元const規(guī)定的事件:編譯器只用去尋找有沒有對數(shù)據(jù)成員的賦值就可以了。另外,如果我們采用了位元con

18、st,那么,對于一些比較簡單的const對象,我們就可以把它安全的放入ROM中,對于一些程序而言,這無疑是一個很重要的優(yōu)化方式。(關(guān)于優(yōu)化處理,我們到時候?qū)iT進(jìn)行討論) 當(dāng)然,位元const也有缺點(diǎn),要不然,抽象const也就沒有產(chǎn)生的必要了。 首先,位元const的抽象性比抽象const的級別更低!實(shí)際上,大家都知道,一個庫接口的抽象性級別越低,使用這個庫就越困難。 其次,使用位元const的庫接口會暴露庫的一些實(shí)現(xiàn)細(xì)節(jié),而這往往會帶來一些負(fù)面效應(yīng)。所以,在庫接口和程序?qū)崿F(xiàn)細(xì)節(jié)上,我們都應(yīng)該采用抽象const。 有時,我們可能希望對const做出一些其它的解釋,那么,就要注意了,目前,大多數(shù)

19、對const的解釋都是類型不安全的,這里我們就不舉例子了,你可以自己考慮一下,總之,我們盡量避免對const的重新解釋。 (3)放在類內(nèi)部的常量有什么限制? 看看下面這個例子: class A private: const int c3 = 7; / ? static int c4 = 7; / ? static const float c5 = 7; / ? . ; 你認(rèn)為上面的3句對嗎?呵呵,都不對!使用這種類內(nèi)部的初始化語法的時候,常量必須是被一個常量表達(dá)式初始化的整型或枚舉類型,而且必須是static和const形式。這顯然是一個很嚴(yán)重的限制! 那么,我們的標(biāo)準(zhǔn)委員會為什么做這樣的規(guī)定

20、呢?一般來說,類在一個頭文件中被聲明,而頭文件被包含到許多互相調(diào)用的單元去。但是,為了避免復(fù)雜的編譯器規(guī)則,C+要求每一個對象只有一個單獨(dú)的定義。如果C+允許在類內(nèi)部定義一個和對象一樣占據(jù)內(nèi)存的實(shí)體的話,這種規(guī)則就被破壞了。 (4)如何初始化類內(nèi)部的常量? 一種方法就是static 和 const 并用,在內(nèi)部初始化,如上面的例子; 另一個很常見的方法就是初始化列表: class A public: A(int i=0):test(i) private: const int i; ; 還有一種方式就是在外部初始化,例如: class A public: A() private: static

21、const int i;file:/注意必須是靜態(tài)的! ; const int A:i=3; (5)常量與數(shù)組的組合有什么特殊嗎? 我們給出下面的代碼: const int size3=10,20,50; int arraysize2; 有什么問題嗎?對了,編譯通不過!為什么呢? const可以用于集合,但編譯器不能把一個集合存放在它的符號表里,所以必須分配內(nèi)存。在這種情況下,const意味著“不能改變的一塊存儲”。然而,其值在編譯時不能被使用,因?yàn)榫幾g器在編譯時不需要知道存儲的內(nèi)容。自然,作為數(shù)組的大小就不行了:) 你再看看下面的例子: class A public: A(int i=0):

22、test2(1,2) file:/你認(rèn)為行嗎? private: const int test2; ; vc6下編譯通不過,為什么呢? 關(guān)于這個問題,前些時間,njboy問我是怎么回事?我反問他:“你認(rèn)為呢?”他想了想,給出了一下解釋,大家可以看看:我們知道編譯器堆初始化列表的操作是在構(gòu)造函數(shù)之內(nèi),顯式調(diào)用可用代碼之前,初始化的次序依據(jù)數(shù)據(jù)聲明的次序。初始化時機(jī)應(yīng)該沒有什么問題,那么就只有是編譯器對數(shù)組做了什么手腳!其實(shí)做什么手腳,我也不知道,我只好對他進(jìn)行猜測:編譯器搜索到test發(fā)現(xiàn)是一個非靜態(tài)的數(shù)組,于是,為他分配內(nèi)存空間,這里需要注意了,它應(yīng)該是一下分配完,并非先分配test0,然后利

23、用初始化列表初始化,再分配test1,這就導(dǎo)致數(shù)組的初始化實(shí)際上是賦值!然而,常量不允許賦值,所以無法通過。 呵呵,看了這一段冠冕堂皇的話,真讓我笑死了!njboy別怪我揭你短呀:)我對此的解釋是這樣的:C+標(biāo)準(zhǔn)有一個規(guī)定,不允許無序?qū)ο笤陬悆?nèi)部初始化,數(shù)組顯然是一個無序的,所以這樣的初始化是錯誤的!對于他,只能在類的外部進(jìn)行初始化,如果想讓它通過,只需要聲明為靜態(tài)的,然后初始化。 這里我們看到,常量與數(shù)組的組合沒有什么特殊!一切都是數(shù)組惹的禍! (6)this指針是不是const類型的? this指針是一個很重要的概念,那該如何理解她呢?也許這個話題太大了,那我們縮小一些:this指針是個什

24、么類型的?這要看具體情況:如果在非const成員函數(shù)中,this指針只是一個類類型的;如果在const成員函數(shù)中,this指針是一個const類類型的;如果在volatile成員函數(shù)中,this指針就是一個volatile類類型的。 (7)const到底是不是一個重載的參考對象? 先看一下下面的例子: class A . void f(int i) .file:/一個函數(shù) void f(int i) const .file:/上一個函數(shù)的重載 . ; 上面是重載是沒有問題的了,那么下面的呢? class A . void f(int i) .file:/一個函數(shù) void f(const in

25、t i) .file:/? . ; 這個是錯誤的,編譯通不過。那么是不是說明內(nèi)部參數(shù)的const不予重載呢?再看下面的例子: class A . void f(int& ) .file:/一個函數(shù) void f(const int& ) .file:/? . ; 這個程序是正確的,看來上面的結(jié)論是錯誤的。為什么會這樣呢?這要涉及到接口的透明度問題。按值傳遞時,對用戶而言,這是透明的,用戶不知道函數(shù)對形參做了什么手腳,在這種情況下進(jìn)行重載是沒有意義的,所以規(guī)定不能重載!當(dāng)指針或引用被引入時,用戶就會對函數(shù)的操作有了一定的了解,不再是透明的了,這時重載是有意義的,所以規(guī)定可以重載。 (8)什么情況

26、下為const分配內(nèi)存? 以下是我想到的可能情況,當(dāng)然,有的編譯器進(jìn)行了優(yōu)化,可能不分配內(nèi)存。 A、作為非靜態(tài)的類成員時; B、用于集合時; C、被取地址時; D、在main函數(shù)體內(nèi)部通過函數(shù)來獲得值時; E、const的 class或struct有用戶定義的構(gòu)造函數(shù)、析構(gòu)函數(shù)或基類時;。 F、當(dāng)const的長度比計算機(jī)字長還長時; G、參數(shù)中的const; H、使用了extern時。 不知道還有沒有其他情況,歡迎高手指點(diǎn):) (9)臨時變量到底是不是常量? 很多情況下,編譯器必須建立臨時對象。像其他任何對象一樣,它們需要存儲空間而且必須被構(gòu)造和刪除。區(qū)別是我們從來看不到編譯器負(fù)責(zé)決定它們的去

27、留以及它們存在的細(xì)節(jié)。對于C+標(biāo)準(zhǔn)草案而言:臨時對象自動地成為常量。因?yàn)槲覀兺ǔ=佑|不到臨時對象,不能使用與之相關(guān)的信息,所以告訴臨時對象做一些改變有可能會出錯。當(dāng)然,這與編譯器有關(guān),例如:vc6、vc7都對此作了擴(kuò)展,所以,用臨時對象做左值,編譯器并沒有報錯。 (10)與static搭配會不會有問題? 假設(shè)有一個類: class A public: . static void f() const . . ; 我們發(fā)現(xiàn)編譯器會報錯,因?yàn)樵谶@種情況下static不能夠與const共存! 為什么呢?因?yàn)閟tatic沒有this指針,但是const修飾this指針,所以. (11)如何修改常量? 有

28、時候我們卻不得不對類內(nèi)的數(shù)據(jù)進(jìn)行修改,但是我們的接口卻被聲明了const,那該怎么處理呢?我對這個問題的看法如下: 1)標(biāo)準(zhǔn)用法:mutable class A public: A(int i=0):test(i) void SetValue(int i)const test=i; private: mutable int test;file:/這里處理! ; 2)強(qiáng)制轉(zhuǎn)換:const_cast class A public: A(int i=0):test(i) void SetValue(int i)const const_cast (test)=i; /這里處理! private: in

29、t test; ; 3)靈活的指針:int* class A public: A(int i=0):test(i) void SetValue(int i)const *test=i; private: int* test;file:/這里處理! ; 4)未定義的處理 class A public: A(int i=0):test(i) void SetValue(int i)const int *p=(int*)&test; *p=i; /這里處理! private: int test; ; 注意,這里雖然說可以這樣修改,但結(jié)果是未定義的,避免使用! 5)內(nèi)部處理:this指針 class

30、A public: A(int i=0):test(i) void SetValue(int i)const (A*)this)-test=i; /這里處理! private: int test; ; 6)最另類的處理:空間布局 class A public: A(int i=0):test(i),c(a) private: char c; const int test; ; int main() A a(3); A* pa=&a; char* p=(char*)pa; int* pi=(int*)(p+4);/利用邊緣調(diào)整 *pi=5;file:/此處改變了test的值! return 0;

31、 雖然我給出了6中方法,但是我只是想說明如何更改,但出了第一種用法之外,另外5種用法,我們并不提倡,不要因?yàn)槲疫@么寫了,你就這么用,否則,我真是要誤人子弟了:) (12)最后我們來討論一下常量對象的動態(tài)創(chuàng)建。 既然編譯器可以動態(tài)初始化常量,就自然可以動態(tài)創(chuàng)建,例如: const int* pi=new const int(10); 這里要注意2點(diǎn): 1)const對象必須被初始化!所以(10)是不能夠少的。 2)new返回的指針必須是const類型的。 那么我們可不可以動態(tài)創(chuàng)建一個數(shù)組呢? 答案是否定的,因?yàn)閚ew內(nèi)置類型的數(shù)組,不能被初始化。 這里我們忽視了數(shù)組是類類型的,同樣對于類內(nèi)部數(shù)組

32、初始化我們也做出了這樣的忽視,因?yàn)檫@涉及到數(shù)組的問題,我們以后再討論。 淺析C+里面的宏收藏說到宏,恐怕大家都能說出點(diǎn)東西來:一種預(yù)處理,沒有分號(真的嗎?)。然后呢?嗯.茫然中.好吧,我們就從這開始說起。最常見的宏恐怕是#include了,其次就是#define還有.還是從宏的用途分類吧:1、#include 主要用于包含引用文件,至今其地位無人能替代;2、注釋掉代碼。例如: #if 0 . #endif; 這種機(jī)制是目前注釋掉代碼的最佳選擇,為摩托羅拉公司員工所普遍采用;3、代碼版本管理。例如: #ifdef DEBUGfile:/調(diào)試版本 #elsefile:/非調(diào)試版本 #endif;

33、4、聲明宏。例如: #define DECLARE_MESSAGE(x) x();x()file:/有沒有分號?哈哈 /. class A public: DECLARE_MESSAGE(A); . 想起什么了,呵呵:)對,VC里面有好多這樣的東東,有空我會寫我的VC歷程,到時候會把VC里的各種宏詳細(xì)的解釋一下,那可是一個龐大的工程:)5、符號常量。例如: #define PI 3.141596、內(nèi)聯(lián)函數(shù)。例如: #define CLEAR(x) (x)=0)7、泛型函數(shù)。例如: #define ABS(x) (x)0? (x):-(x) x=3 沒問題! x=1.3 也沒問題! 如果是這樣呢

34、: #include #define A(x) (x)0? (x):-(x) void main() int i=-1;coutA(1)endl;coutA(+i)endl; 有問題了,不過以后再說,大概講const or inline 時會說的:)8、泛型類型。例如: #define Stack(T) Stack_ #T #define Stackdeclare(T) class Stack(T) . Stackdeclare(int); Stackdeclare(char); . Stack(int) s1; Stack(char) s2;9、語法擴(kuò)展。例如: Set s;/假設(shè)Set為一個描述集合的類 int i; FORALL(i,s); . 宏最大的問題便是易引起沖突,例如: libA.h: #define MACRO stuff 同時: libB.h: #define MACRO stuff 下面我們對他們進(jìn)行引用: user.cpp: #include libA.h #include libB.h . 糟糕,出現(xiàn)了重定義! 還有一種沖突的可能: libB.h:(沒有定義宏MACRO) class x void MACRO(); .; 那么程序運(yùn)行期間,libA.h中的宏講會改變libB.h中的成員函數(shù)的名字,導(dǎo)致不可預(yù)料的結(jié)果。 宏的另一個問題

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論