• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            堅(jiān)持學(xué)習(xí)/暴露問(wèn)題/不斷提升

            c++/設(shè)計(jì)模式/算法結(jié)構(gòu)/系統(tǒng)
            posts - 2, comments - 20, trackbacks - 0, articles - 0

            摘要:

            Sizeof的作用非常簡(jiǎn)單:求對(duì)象或者類(lèi)型的大小。然而sizeof又非常復(fù)雜,它涉及到很多特殊情況,本篇把這些情況分門(mén)別類(lèi),總結(jié)出了sizeof的10個(gè)特性:

            (0)sizeof是運(yùn)算符,不是函數(shù);

            (1)sizeof不能求得void類(lèi)型的長(zhǎng)度;

            (2)sizeof能求得void類(lèi)型的指針的長(zhǎng)度;

            (3)sizeof能求得靜態(tài)分配內(nèi)存的數(shù)組的長(zhǎng)度!

            (4)sizeof不能求得動(dòng)態(tài)分配的內(nèi)存的大小!

            (5)sizeof不能對(duì)不完整的數(shù)組求長(zhǎng)度;

            (6)當(dāng)表達(dá)式作為sizeof的操作數(shù)時(shí),它返回表達(dá)式的計(jì)算結(jié)果的類(lèi)型大小,但是它不對(duì)表達(dá)式求值!

            (7)sizeof可以對(duì)函數(shù)調(diào)用求大小,并且求得的大小等于返回類(lèi)型的大小,但是不執(zhí)行函數(shù)體!

            (8)sizeof求得的結(jié)構(gòu)體(及其對(duì)象)的大小并不等于各個(gè)數(shù)據(jù)成員對(duì)象的大小之和!

            (9)sizeof不能用于求結(jié)構(gòu)體的位域成員的大小,但是可以求得包含位域成員的結(jié)構(gòu)體的大小!

            概述:

            Sizeof是C/C++中的關(guān)鍵字,它是一個(gè)運(yùn)算符,其作用是取得一個(gè)對(duì)象(數(shù)據(jù)類(lèi)型或者數(shù)據(jù)對(duì)象)的長(zhǎng)度(即占用內(nèi)存的大小,byte為單位)。其中類(lèi)型包含基本數(shù)據(jù)類(lèi)型(不包括void)、用戶自定義類(lèi)型(結(jié)構(gòu)體、類(lèi))、函數(shù)類(lèi)型。數(shù)據(jù)對(duì)象是指用前面提到的類(lèi)型定義的普通變量和指針變量(包含void指針)。不同類(lèi)型的數(shù)據(jù)的大小在不同的平臺(tái)下有所區(qū)別,但是c標(biāo)準(zhǔn)規(guī)定所有編譯平臺(tái)都應(yīng)該保證sizeof(char)等于1。關(guān)于sizeof的更多概述你可以在msdn總輸入sizeof進(jìn)行查詢。

            看了上面這些,或許你看了沒(méi)有多少感覺(jué)。沒(méi)關(guān)系,下面我將詳細(xì)列出sizeof的諸多特性,這些特性是造成sizeof是一個(gè)較刁鉆的關(guān)鍵字的原因:

            十大特性:

            特性0:sizeof是運(yùn)算符,不是函數(shù)

            這個(gè)特性是sizeof的最基本特性,后面的很多特性都是受到這個(gè)特性的影響,正因?yàn)閟izeof不是函數(shù),因此我們不把它所要求得長(zhǎng)度的對(duì)象叫做參數(shù),我本人習(xí)慣上叫做操作數(shù)(這不嚴(yán)謹(jǐn),但是有助于我記住sizeof是個(gè)操作符)。

            特性1:sizeof不能求得void類(lèi)型的長(zhǎng)度

            是的,你不能用sizeof(void),這將導(dǎo)致編譯錯(cuò)誤:illegal sizeof operand。事實(shí)上你根本就無(wú)法聲明void類(lèi)型的變量,不信你就試試void a;這樣的語(yǔ)句,編譯器同樣會(huì)報(bào)錯(cuò):illegal use of type 'void'。或許你要問(wèn)為什么,很好,學(xué)東西不能只知其然,還要知其所以然。我們知道聲明變量的一個(gè)重要作用就是告訴編譯器該變量需要多少存儲(chǔ)空間。然而,void是“空類(lèi)型”,什么是空類(lèi)型呢,你可以理解成不知道存儲(chǔ)空間大小的類(lèi)型。既然編譯器無(wú)法確定void類(lèi)型的變量的存儲(chǔ)大小,那么它自然不讓你聲明這樣的變量。當(dāng)然了,聲明void類(lèi)型的指針是可以的!這就是特性2的內(nèi)容。

            特性2:sizeof能求得void類(lèi)型的指針的長(zhǎng)度

            在特性1中說(shuō)過(guò),可以申明void類(lèi)型的指針,也就是說(shuō)編譯器可以確定void類(lèi)型的指針?biāo)加玫拇鎯?chǔ)空間。事實(shí)上確實(shí)如此,目前,幾乎所有平臺(tái)上的所有版本的編譯器都把指針的大小看做4byte,不信你試試sizeof(int*);sizeof(void*);sizeof(double*);sizeof(Person*);等等,它們都等于4!為什么呢?問(wèn)得好,我將盡全力對(duì)此作出解釋?zhuān)浩鋵?shí)指針也是變量,只不過(guò)這個(gè)變量很特殊,它是存放其他變量的地址的變量。又由于目前32位計(jì)算機(jī)平臺(tái)上的程序段的尋址范圍都是4GB,尋址的最小單元是byte,4GB等于232Byte,這么多的內(nèi)存其地址如果編碼呢,只需要用32個(gè)bit就行了,而32bit = 32/8 = 4byte,也就是說(shuō)只需要4byte就能存儲(chǔ)這些內(nèi)存的地址了。因此對(duì)任何類(lèi)型的指針變量進(jìn)行sizeof運(yùn)算其結(jié)果就是4!

            特性3:sizeof能求得靜態(tài)分配內(nèi)存的數(shù)組的長(zhǎng)度!

            Int a[10];int n = sizeof(a);假設(shè)sizeof(int)等于4,則n= 10*4=40;特別要注意:char ch[]=”abc”;sizeof(ch);結(jié)果為4,注意字符串?dāng)?shù)組末尾有’\0’!通常我們可以利用sizeof來(lái)計(jì)算數(shù)組中包含的元素個(gè)數(shù),其做法是:int n = sizeof(a)/sizeof(a[0]);

            非常需要注意的是對(duì)函數(shù)的形參數(shù)組使用sizeof的情況。舉例來(lái)說(shuō),假設(shè)有如下的函數(shù):

            void fun(int array[10])

            {

                     int n = sizeof(array);

            }

            你會(huì)覺(jué)得在fun內(nèi),n的值為多少呢?如果你回答40的話,那么我很遺憾的告訴你,你又錯(cuò)了。這里n等于4,事實(shí)上,不管形參是int的型數(shù)組,還是float型數(shù)組,或者其他任何用戶自定義類(lèi)型的數(shù)組,也不管數(shù)組包含多少個(gè)元素,這里的n都是4!為什么呢?原因是在函數(shù)參數(shù)傳遞時(shí),數(shù)組被轉(zhuǎn)化成指針了,或許你要問(wèn)為什么要轉(zhuǎn)化成指針,原因可以在很多書(shū)上找到,我簡(jiǎn)單說(shuō)一下:假如直接傳遞整個(gè)數(shù)組的話,那么必然涉及到數(shù)組元素的拷貝(實(shí)參到形參的拷貝),當(dāng)數(shù)組非常大時(shí),這會(huì)導(dǎo)致函數(shù)執(zhí)行效率極低!而只傳遞數(shù)組的地址(即指針)那么只需要拷貝4byte

            特性4:sizeof不能求得動(dòng)態(tài)分配的內(nèi)存的大小!

            假如有如下語(yǔ)句:int* a = new int[10];int n = sizeof(a);那么n的值是多少呢?是40嗎?答案是否定的!其實(shí)n等于4,因?yàn)閍是指針,在特性2中講過(guò):在32位平臺(tái)下,所有指針的大小都是4byte!切記,這里的a與特性3中的a并不一樣!很多人(甚至一些老師)都認(rèn)為數(shù)組名就是指針,其實(shí)不然,二者有很多區(qū)別的,要知詳情,請(qǐng)看《c專(zhuān)家編程》。通過(guò)特性3和特性4,我們看到了數(shù)組和指針有著千絲萬(wàn)縷的關(guān)系,這些關(guān)系也是導(dǎo)致程序潛在錯(cuò)誤的一大因素,關(guān)于指針與數(shù)組的關(guān)系問(wèn)題我將在《C/C++刁鉆問(wèn)題各個(gè)擊破之指針與數(shù)組的秘密》一文中進(jìn)行詳細(xì)介紹。

            特性3指出sizeof能求靜態(tài)分配的數(shù)組的大小,而特性4說(shuō)明sizeof不能求的動(dòng)態(tài)分配的內(nèi)存的大小。于是有人認(rèn)為sizeof是編譯時(shí)進(jìn)行求值的,并給出理由:語(yǔ)句int array[sizeof(int)*10];能編譯通過(guò),而很多書(shū)上都說(shuō)過(guò)數(shù)組大小是編譯時(shí)就確定下來(lái)的,既然前面的語(yǔ)句能編譯通過(guò),所以認(rèn)為sizeof是編譯時(shí)進(jìn)行求值的。經(jīng)過(guò)進(jìn)一步測(cè)試我發(fā)現(xiàn)這個(gè)結(jié)論有些武斷!至少是有些不嚴(yán)謹(jǐn)!因?yàn)樵趯?shí)現(xiàn)了c99標(biāo)準(zhǔn)的編譯器(如DEV C++)中可以定義動(dòng)態(tài)數(shù)組,即:語(yǔ)句:int num;cin>>num; int arrary[num];是對(duì)的(注意在vc6.0中是錯(cuò)的)。因此我就在DEV C++中對(duì)剛才的array利用語(yǔ)句int n =sizeof(array);cout<<n<<endl來(lái)求大小,結(jié)果編譯通過(guò),運(yùn)行時(shí)輸入num的值10之后,輸出n等于40!在這里很明顯num的值是運(yùn)行時(shí)才輸入的,因此sizeof不可能在編譯時(shí)就求得array的大小!這樣一來(lái)sizeof又變成是運(yùn)行時(shí)求值的了。

            那么到底sizeof是編譯時(shí)求值還是運(yùn)行時(shí)求值呢?最開(kāi)初c標(biāo)準(zhǔn)規(guī)定sizeof只能編譯時(shí)求值,后來(lái)c99又補(bǔ)充規(guī)定sizeof可以運(yùn)行時(shí)求值。但值得注意的是,即便是在實(shí)現(xiàn)了c99標(biāo)準(zhǔn)的DEV C++中仍然不能用sizeof求得動(dòng)態(tài)分配的內(nèi)存的大小!

            特性5:sizeof不能對(duì)不完整的數(shù)組求長(zhǎng)度!

            在闡述該特性之前,我們假設(shè)有兩個(gè)源文件:file1.cpp和file2.cpp,其中file1.cpp中有如下的定義:

            int arrayA[10] = {1,2,3,4,5,6,7,8,9,10};

            int arrayB[10] = {11,12,13,14,15,16,17,18,19,20};

            file2.cpp包含如下幾個(gè)語(yǔ)句:

                     extern arrayA[];

                     extern arrayB[10];

                     cout<<sizeof(arrayA)<<endl;            //編譯出錯(cuò)!!

                     cout<<sizeof(arrayB)<<endl;

            在file2.cpp中第三條語(yǔ)句編譯出錯(cuò),而第條語(yǔ)句正確,并且能輸出40!為什么呢?原因就是sizeof(arrayA)試圖求不完整數(shù)組的大小。這里的不完整的數(shù)組是指數(shù)組大小沒(méi)有確定的數(shù)組!sizeof運(yùn)算符的功能就是求某種對(duì)象的大小,然而聲明:extern int arrayA[]只是告訴編譯器arrayA是一個(gè)整型數(shù)組,但是并沒(méi)告訴編譯器它包含多少個(gè)元素,因此對(duì)file2.cpp中的sizeof來(lái)說(shuō)它無(wú)法求出arrayA的大小,所以編譯器干脆不讓你通過(guò)編譯。

            那為什么sizeof(arrayB)又可以得到arraryB的大小呢?關(guān)鍵就在于在file2.cpp中其聲明時(shí)使用extern int arrayB[10]明確地告訴編譯器arrayB是一個(gè)包含10個(gè)元素的整型數(shù)組,因此大小是確定的。

            到此本特性講解差不多要結(jié)束了。其實(shí)本問(wèn)題還能引申出連接和編譯等知識(shí)點(diǎn),但是目前我暫時(shí)還沒(méi)自信對(duì)這兩個(gè)知識(shí)點(diǎn)進(jìn)行詳細(xì)的,徹底的講解,因此不便在此班門(mén)弄斧,不久的將來(lái)我會(huì)在本系列中加上相關(guān)問(wèn)題的闡述。

            特性6:當(dāng)表達(dá)式作為sizeof的操作數(shù)時(shí),它返回表達(dá)式的計(jì)算結(jié)果的類(lèi)型大小,但是它不對(duì)表達(dá)式求值!

            為了說(shuō)明這個(gè)問(wèn)題,我們來(lái)看如下的程序語(yǔ)句:

            char ch = 1;

                     int num=1;

                     int n1 = sizeof(ch+num);

                     int n2 = sizeof(ch = ch+num);

            假設(shè)char占用1byte,int占用4byte,那么執(zhí)行上面的程序之后,n1,n2,ch的值是多少呢?我相信有不少人會(huì)認(rèn)為n1與n2相等,也有不少人認(rèn)為ch等于2,事實(shí)這些人都錯(cuò)了。事實(shí)上n1等于4,n2等于1,ch等于1,為什么呢?請(qǐng)看分析:

            由于默認(rèn)類(lèi)型轉(zhuǎn)換的原因,表達(dá)式ch+num的計(jì)算結(jié)果的類(lèi)型是int,因此n1的值為4!而表達(dá)式ch=ch+num;的結(jié)果的類(lèi)型是char,記住雖然在計(jì)算ch+num時(shí),結(jié)果為int,但是當(dāng)把結(jié)果賦值給ch時(shí)又進(jìn)行了類(lèi)型轉(zhuǎn)換,因此表達(dá)式的最終類(lèi)型還是char,所以n2等于1。n1,n2的值分別為4和1,其原因正是因?yàn)閟izeof返回的是表達(dá)式計(jì)算結(jié)果的類(lèi)型大小,而不是表達(dá)式中占用最大內(nèi)存的變量的類(lèi)型大小!

            對(duì)于n2=sizeof(ch =ch+num);乍一看該程序貌似實(shí)現(xiàn)了讓ch加上num并賦值給ch的功能,事實(shí)并非如此!由于sizeof只關(guān)心類(lèi)型大小,所以它自然不應(yīng)該對(duì)表達(dá)式求值,否則有畫(huà)蛇添足之嫌了。但是,在支持變長(zhǎng)數(shù)組定義的(即實(shí)現(xiàn)了c99標(biāo)準(zhǔn)的)編譯器(dev C++)中執(zhí)行了int len = 3;cout<<sizeof(int [++len])<<”,”<<len;輸出是多少呢?答案是16,4!這里的++len卻執(zhí)行了!很不可理喻吧?這到底是為什么呢?我翻閱了《The New C Standard》一書(shū),這主要是由于可變長(zhǎng)度的數(shù)組的長(zhǎng)度需要在其長(zhǎng)度表達(dá)式求值之后才能確定大小,因此上述情況下,sizeof中的++len執(zhí)行了。

            正是因?yàn)閟izeof的操作數(shù)中的某些表達(dá)式會(huì)被執(zhí)行,而有些表達(dá)式不會(huì)被執(zhí)行,這里告誡各位,盡量不要在sizeof中直接對(duì)表達(dá)式求大小,以免出現(xiàn)錯(cuò)誤,你可以將sizeof(ch = ch+num);改寫(xiě)成 ch = ch +num;sizeof(ch);雖然多了一條語(yǔ)句,看似冗余了,其實(shí)好處多多:首先更加清晰明了,其次不會(huì)出現(xiàn)ch等于1這樣的錯(cuò)誤(假設(shè)程序的邏輯本身就是要執(zhí)行ch = ch +num;)。

            特性7:sizeof可以對(duì)函數(shù)調(diào)用求大小,并且求得的大小等于返回類(lèi)型的大小,但是不執(zhí)行函數(shù)體!

            假設(shè)有如下函數(shù)(是一個(gè)寫(xiě)得很不好的函數(shù),但是能很好的說(shuō)明需要闡述的問(wèn)題):

            int fun(int& num,const int& inc)

            {

                     float div = 2.0;

                     double ret =0;

                     num = num+inc;

                     ret = num/div;

                     return ret;

            }那么語(yǔ)句:

            int a = 3;

                     int b = 5;

                     cout<<sizeof(fun(a,b))<<endl;

                     cout<<a<<endl;輸出多少呢?不同的人會(huì)給出不同的答案,我將對(duì)sizeof(fun(a,b))的值和a的值分別進(jìn)行討論:

            首先sizeof(fun(a,b))的值:其正確是4,因?yàn)橛胹izeof求函數(shù)調(diào)用的大小時(shí),它得到的是函數(shù)返回類(lèi)型的大小,而fun(a,b)的返回類(lèi)型是int,sizeof(int)等于4。很多人把函數(shù)的返回類(lèi)型返回值的類(lèi)型弄混淆了,認(rèn)為sizeof(fun(a,b))的值是8,因?yàn)楹瘮?shù)返回值是ret,而ret被定義成double,sizeof(doube)等于8。注意,雖然函數(shù)返回值類(lèi)型是double,但是在函數(shù)返回時(shí),將該值進(jìn)行了類(lèi)型轉(zhuǎn)換(這里的轉(zhuǎn)換不安全)。也有人錯(cuò)誤的認(rèn)為sizeof(fun(a,b))的值是12,它們的理由是:fun內(nèi)部定義了兩個(gè)局部變量,一個(gè)是float一個(gè)是double,而sizeof(float)+sizeof(doube)= 4+8=12。這樣的答案看似很合理,其實(shí)他們是錯(cuò)誤地認(rèn)為這里的sizeof是在求函數(shù)內(nèi)部的變量的大小了。這當(dāng)然是錯(cuò)誤的。

            接下來(lái)看a的值:其正確答案是3!還記得特性6嗎?這里很類(lèi)似,sizeof的操作對(duì)象是函數(shù)調(diào)用時(shí),它不執(zhí)行函數(shù)體!為此,建議大家不要把函數(shù)體放在sizeof后面的括號(hào)里,這樣容易讓人誤以為函數(shù)執(zhí)行了,其實(shí)它根本沒(méi)執(zhí)行。

            既然對(duì)函數(shù)條用使用sizeof得到的是函數(shù)返回類(lèi)型的大小,那么很自然能得出這樣的結(jié)論:不能對(duì)返回類(lèi)型為void的函數(shù)使用sizeof求其大小!原因請(qǐng)參考特性1。同理,對(duì)返回類(lèi)型是任何類(lèi)型的指針的函數(shù)調(diào)用使用sizeof求得的大小都為4,原因請(qǐng)參考特性2。

            最后我們來(lái)看看這樣的語(yǔ)句:cout<<sizeof(fun);其答案是多少呢?其實(shí)它得不到答案,原因是編譯就通不過(guò)!最開(kāi)始,我以為能輸出答案4,因?yàn)槲艺J(rèn)為fun是函數(shù)名,而我知道函數(shù)名就是函數(shù)的地址,地址就是指針,于是我認(rèn)為sizeof(fun)其實(shí)就是對(duì)一個(gè)指針求大小,根據(jù)特性2,任何指針的大小都是4。可是當(dāng)我去驗(yàn)證時(shí),編譯器根本不讓我通過(guò)!這個(gè)是為什么呢?我一時(shí)半會(huì)想不到,所以還請(qǐng)朋友們補(bǔ)充!

            特性8:sizeof求得的結(jié)構(gòu)體(及其對(duì)象)的大小并不等于各個(gè)數(shù)據(jù)成員對(duì)象的大小之和!

            結(jié)構(gòu)體的大小跟結(jié)構(gòu)體成員對(duì)齊有密切關(guān)系,而并非簡(jiǎn)單地等于各個(gè)成員的大小之和!比如對(duì)如下結(jié)構(gòu)體兩個(gè)結(jié)構(gòu)體A、B使用sizeof的結(jié)果分別是:16,24。可以看出sizeof(B)并不等于sizeof(int)+sizeof(double)+sizeof(int)=16。

            struct A{

                     int num1;

                     int num2;

                     double num3;

            };

            struct B{

                     int num1;

                     double num3;

                     int num2;

            };

            如果您不了解結(jié)構(gòu)體的成員對(duì)齊,你會(huì)感到非常驚訝:結(jié)構(gòu)體A和B中包含的成員都一樣,只不過(guò)順序不同而已,為什么其大小不一樣呢?要解釋這個(gè)問(wèn)題,就要了解結(jié)構(gòu)體成員對(duì)齊的規(guī)則,由于結(jié)構(gòu)體成員對(duì)齊非常復(fù)雜,我將用專(zhuān)題——C/C++刁鉆問(wèn)題各個(gè)擊破之位域和成員對(duì)齊——進(jìn)行講解,這里我只簡(jiǎn)單地介紹其規(guī)則:

            1、 結(jié)構(gòu)體的大小等于結(jié)構(gòu)體內(nèi)最大成員大小的整數(shù)倍

            2、 結(jié)構(gòu)體內(nèi)的成員的首地址相對(duì)于結(jié)構(gòu)體首地址的偏移量是其類(lèi)型大小的整數(shù)倍,比如說(shuō)double型成員相對(duì)于結(jié)構(gòu)體的首地址的地址偏移量應(yīng)該是8的倍數(shù)。

            3、 為了滿足規(guī)則1和2編譯器會(huì)在結(jié)構(gòu)體成員之后進(jìn)行字節(jié)填充!

             

            基于上面三個(gè)規(guī)則我們來(lái)看看為什么sizeof(B)等于24:首先假設(shè)結(jié)構(gòu)體的首地址為0,第一個(gè)成員num1的首地址是0(滿足規(guī)則2,前面無(wú)須字節(jié)填充,事實(shí)上結(jié)構(gòu)體絕對(duì)不會(huì)在第一個(gè)數(shù)據(jù)成員前面進(jìn)行字節(jié)填充),它的類(lèi)型是int,因此它占用地址空間0——3。第二個(gè)成員num3是double類(lèi)型,它占用8個(gè)字節(jié),由于之前的num1只占用了4個(gè)字節(jié),為了滿足規(guī)則2,需要使用規(guī)則3在num1后面填充4個(gè)字節(jié)(4——7),使得num3的起始地址偏移量為8,因此num3占用的地址空間是:8——15。第三個(gè)成員num2是int型,其大小為4,由于num1和num3一共占用了16個(gè)字節(jié),此時(shí)無(wú)須任何填充就能滿足規(guī)則2。因此num2占用的地址空間是16——19。那么是不是結(jié)構(gòu)體的總大小就是0——19共20個(gè)字節(jié)呢?請(qǐng)注意,別忘了規(guī)則1!由于結(jié)構(gòu)體內(nèi)最大成員是double占用8個(gè)字節(jié),因此最后還需要在num2后面填充4個(gè)字節(jié),使得結(jié)構(gòu)體總體大小為24。

            按照上面的三個(gè)規(guī)則和分析過(guò)程,你可以很容易地知道為什么sizeof(A)等于16。特別需要說(shuō)明的是,我這里給出了三個(gè)結(jié)論性的規(guī)則,而沒(méi)有闡述為什么要這樣。你或許有很多疑問(wèn):為什么要結(jié)構(gòu)體成員對(duì)齊,為什么要定義規(guī)則1等。如果你有這樣的疑問(wèn),并嘗試去弄清楚的話,那么我敢斷言,不久的將來(lái)你必定會(huì)有大成就,至少在學(xué)習(xí)c++上是這樣。前面說(shuō)過(guò),我會(huì)再寫(xiě)一篇專(zhuān)題:C/C++刁鉆問(wèn)題各個(gè)擊破之位域和成員對(duì)齊來(lái)詳細(xì)回答這些問(wèn)題,如果你急于要弄明白,那么你可以參考其他資料,比如說(shuō)《高質(zhì)量c++程序設(shè)計(jì)指南》。

            最后再提醒一點(diǎn),在進(jìn)行設(shè)計(jì)時(shí),最好仔細(xì)安排結(jié)構(gòu)體中各個(gè)成員的順序,因?yàn)槟阋呀?jīng)看到了上面的結(jié)構(gòu)體B與結(jié)構(gòu)體A包含的成員相同,只不過(guò)順序略有差異,最終就導(dǎo)致了B比A多消耗了50%的空間,假如在工程中需要定義該結(jié)構(gòu)體的數(shù)組,多消耗的空降將是巨大的。即使將來(lái)內(nèi)存降價(jià)為白菜價(jià)格,你也不要忽視這個(gè)問(wèn)題,勤儉節(jié)約是中國(guó)人民的優(yōu)良傳統(tǒng),我們應(yīng)該繼承和保持!

            特性9:sizeof不能用于求結(jié)構(gòu)體的位域成員的大小,但是可以求得包含位域成員的結(jié)構(gòu)體的大小!

            首先解釋一下什么是位域:類(lèi)型的大小都是以字節(jié)(byte)為基本單位的,比如sizeof(char)為1byte,sizeof(int)為4byte等。我們知道某個(gè)類(lèi)型的大小確定了該類(lèi)型所能定義的變量的范圍,比如sizeof(char)為1byte,而1byte等于8bit,所以char類(lèi)型的變量范圍是-128——127,或者0——255(unsigned char),總之它只能定義28=256個(gè)數(shù)!然而,要命的是bool類(lèi)型只取值true和false,按理所只用1bit(即1/8byte)就夠了,但事實(shí)上sizeof(bool)等于1。因此我們可以認(rèn)為bool變量浪費(fèi)了87.5%的存儲(chǔ)空間!這在某些存儲(chǔ)空間有限的設(shè)備(比如嵌入式設(shè)備)上是不合適的,為此需要提供一種能對(duì)變量的存儲(chǔ)空間精打細(xì)算的機(jī)制,這就是位域。簡(jiǎn)單來(lái)說(shuō),在結(jié)構(gòu)體的成員變量后面跟上的一個(gè)冒號(hào)+一個(gè)整數(shù),就代表位域,請(qǐng)看如下的結(jié)構(gòu)體:

            Struct A

            {

                     Bool b:1;

                     char ch1:4;

                     char ch2:4;

            }item; 其中b,ch1,ch2都是位域成員,而i是普通成員。該結(jié)構(gòu)體的試圖讓bool類(lèi)型的變量b只占用1個(gè)bit,讓ch1和ch2分別只占用4個(gè)bit,以此來(lái)達(dá)到對(duì)內(nèi)存精打細(xì)算的功能(事實(shí)上使用位域?qū)?nèi)存精打細(xì)算有時(shí)候能成功,有時(shí)候卻未必,我將《C/C++刁鉆問(wèn)題各個(gè)擊破之位域和成員對(duì)齊》進(jìn)行論述)。另外需要特別注意的是:c語(yǔ)言規(guī)定位域只能用于int,signed int或者unsigned int類(lèi)型,C++又補(bǔ)充了char和long類(lèi)型!你不能這樣使用位域:float f:8;這是不能通過(guò)編譯的。并且位域變量不能在函數(shù)或者全局區(qū)定義,只能在結(jié)構(gòu)體,自定義類(lèi),聯(lián)合(union)中使用!

            基于上面的結(jié)構(gòu)體,語(yǔ)句sizeof(item.b)和sizeof(item.ch1)等對(duì)位域成員求大小的語(yǔ)句均不能通過(guò)編譯。其原因能再本篇的概論中找到:sizeof以byte為單位返回操作數(shù)的大小!

            那么愛(ài)學(xué)好問(wèn)的你可能要問(wèn),sizeof(A)能否通過(guò)編譯呢?如何能,其結(jié)果又是多少呢?這是兩給非常好的問(wèn)題,事實(shí)上我之前沒(méi)有看到任何關(guān)于這方面的論述(可能是我看的資料不足),我正是在看到sizeof(item.b)不能通過(guò)編譯時(shí)想到了這兩個(gè)問(wèn)題,然后通過(guò)驗(yàn)證得出了后面的結(jié)論:對(duì)包含位域的結(jié)構(gòu)體是可以使用sizeof求其大小的,但其求值規(guī)則比較復(fù)雜,不僅涉及到成員對(duì)齊,還與具體編譯環(huán)境有關(guān)!在這里你只需要知道可以對(duì)包含位域的結(jié)構(gòu)體使用sizeof求其大小,對(duì)于sizeof是根據(jù)什么規(guī)則來(lái)求這個(gè)大小的問(wèn)題,我將會(huì)在專(zhuān)題:《C/C++刁鉆問(wèn)題各個(gè)擊破之位域和成員對(duì)齊》中進(jìn)行詳細(xì)闡述

            后記:

            至此,本專(zhuān)題差不多該結(jié)束了,需要說(shuō)明的是,這里并沒(méi)有包含所有關(guān)于sizeof的知識(shí)點(diǎn),但是也幾乎包含了所有的容易出錯(cuò)的特性。為了完成該文,我花了斷斷續(xù)續(xù)3天半時(shí)間,想想效率實(shí)在是底下。由于是本系列的第一個(gè)專(zhuān)題,我格外慎重,深怕講錯(cuò)了誤導(dǎo)大家。即便如此,也難免錯(cuò)誤或不妥之處,還請(qǐng)各位朋友指正!

            另外,我有幾句話要對(duì)大學(xué)生朋友們說(shuō):教科書(shū)通常只是教授很基礎(chǔ)的知識(shí),要想深入學(xué)習(xí),還需要翻閱其他資料,比如論文、網(wǎng)絡(luò)資料、論壇博文,最重要的一點(diǎn)是要在學(xué)習(xí)時(shí)經(jīng)常總結(jié)、記錄、歸納,積少成多,這樣堅(jiān)持下來(lái)一定受益匪淺。 @import url(http://www.shnenglu.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

            Feedback

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-09 19:22 by ZhangShine
            準(zhǔn)備寫(xiě)書(shū)么?先頂一個(gè)

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof[未登錄](méi)  回復(fù)  更多評(píng)論   

            2011-08-09 20:52 by kkk
            簡(jiǎn)而言之sizeof是個(gè)編譯期的計(jì)算

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 09:59 by zuhd
            很詳細(xì),質(zhì)量也不錯(cuò),幫頂

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 11:20 by 二狗子_五哥
            @ZhangShine
            呵呵,沒(méi)打算寫(xiě)書(shū)哈,寫(xiě)出來(lái)就是為了交流而已

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 11:23 by 二狗子_五哥
            @kkk
            在支持動(dòng)態(tài)數(shù)組的平臺(tái)上sizeof同樣能計(jì)算數(shù)組的大小,因此不能簡(jiǎn)單地說(shuō)sizeof是編譯時(shí)計(jì)算結(jié)果的,比如在dev C++下如下語(yǔ)句能計(jì)算數(shù)組大小:
            int len;
            cin>>len;
            int array[len];
            cout<<sizeof(array);
            輸出結(jié)果跟你輸入的len的大小有關(guān),這充分說(shuō)明sizeof能在運(yùn)行時(shí)求值!

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 11:23 by 二狗子_五哥
            @zuhd
            謝謝....

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 15:38 by 陳曉
            受教了,哈哈,thank you

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 16:51 by Hsssssss
            @二狗子_五哥
            int len;
            cin>>len;
            int array[len];//這句就該報(bào)錯(cuò)了!len不是編譯期常量,不能當(dāng)靜態(tài)數(shù)組的長(zhǎng)度啊

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 16:58 by Hsssssss
            int len=3;
            cout<<sizeof(int [++len])<<endl;
            //vs.net中編譯通不過(guò)
            //error C2540: non-constant expression as array bound

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 17:14 by 陳昱(CY)
            quote: “因此對(duì)任何類(lèi)型的指針變量進(jìn)行sizeof運(yùn)算其結(jié)果就是4”

            成員函數(shù)指針 不一定是4,詳情見(jiàn)
            http://www.goingware.com/tips/member-pointers.html

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 21:36 by 二狗子_五哥
            @Hsssssss
            我之前說(shuō)得很清楚,必須在支持動(dòng)態(tài)數(shù)組定義的編譯器中才能那么用,c99標(biāo)準(zhǔn)中新增加了動(dòng)態(tài)數(shù)組的定義,vc沒(méi)有完全實(shí)現(xiàn)c99因此不能那么用,但是dev c++可以的。vc,vs不能定義數(shù)組要求其長(zhǎng)度是常量,當(dāng)然不能編譯了,但是dev c++用的是gcc編譯器,它支持動(dòng)態(tài)數(shù)組定義,如果不信的話,你可以在windows環(huán)境下用dev c++編譯器試試,或者在linux環(huán)境下試試

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 21:37 by 瘋狂的面包
            @二狗子_五哥
            你的代碼明顯是錯(cuò)誤的, 又不是動(dòng)態(tài)分配,sizeof顯然是編譯時(shí)確定數(shù)據(jù)的大小的

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 21:38 by 二狗子_五哥
            @Hsssssss
            vs中c/c++編譯器跟vc雷同,不支持動(dòng)態(tài)數(shù)組定義,我舉的例子是有前提的,您不能把那個(gè)前提拋開(kāi)來(lái)看問(wèn)題啊。

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 21:42 by 二狗子_五哥
            @瘋狂的面包
            你在dev c++環(huán)境下,或者gcc編譯器中運(yùn)行過(guò)我的代碼嗎?它是正確的,不同的編譯器實(shí)現(xiàn)不同而已,c標(biāo)準(zhǔn)的所有東西并非每個(gè)編譯器都完全實(shí)現(xiàn)了,而且c/c++標(biāo)準(zhǔn)本身也在發(fā)展中,的確,最初c/c++不支持定義變長(zhǎng)數(shù)組,但是c99增加了相關(guān)內(nèi)容,而dev c++編譯器實(shí)現(xiàn)了這點(diǎn),于是我的代碼在dev c++中就是對(duì)的。

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2011-08-10 21:45 by 二狗子_五哥
            @陳昱(CY)
            非常感謝,我之前沒(méi)考慮到成員函數(shù)的指針問(wèn)題,事實(shí)上我根本不知道這個(gè)問(wèn)題,今天太晚了,明天把你提供的鏈接學(xué)習(xí)一下,然后修改之

            # re: C/C++刁鉆問(wèn)題各個(gè)擊破之細(xì)說(shuō)sizeof  回復(fù)  更多評(píng)論   

            2015-01-06 16:44 by 賈可
            @二狗子_五哥
            這個(gè)我估計(jì)編譯器可能把 sizeof 處理為 sizeof(int) * len 了

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久精品毛片免费观看| 色综合色天天久久婷婷基地| 波多野结衣久久一区二区| 欧美精品久久久久久久自慰| 久久综合综合久久97色| 久久人与动人物a级毛片| 日本久久久精品中文字幕| 蜜桃麻豆www久久国产精品| 精品永久久福利一区二区| 欧美午夜A∨大片久久| 99久久免费国产特黄| 欧美精品九九99久久在观看| 久久综合狠狠色综合伊人| 国产A三级久久精品| 久久亚洲高清综合| 秋霞久久国产精品电影院| 婷婷久久香蕉五月综合加勒比| 久久996热精品xxxx| 97久久超碰成人精品网站| 精品国产乱码久久久久久呢| 久久人人爽人人精品视频| 久久国产精品99久久久久久老狼 | 一本一本久久A久久综合精品| 亚洲国产精品久久| 久久青青草原亚洲av无码app| 奇米影视7777久久精品人人爽| 久久精品国产只有精品66| 久久电影网一区| 久久国产精品成人免费| 99久久99久久精品免费看蜜桃| 亚洲精品无码久久久久久| 思思久久好好热精品国产| 色婷婷久久久SWAG精品| 久久综合狠狠综合久久97色| 久久99精品国产麻豆不卡| 精品久久久久久99人妻| 国内精品久久久久国产盗摄| 狠狠色综合久久久久尤物| 99久久99久久精品国产片| 精品久久久久久无码国产| 精品国产综合区久久久久久 |