內(nèi)存對齊與自定義類型-創(chuàng)新互聯(lián)

一、內(nèi)存對齊

創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的山陽網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

 (一)、為什么會有內(nèi)存對齊?

  1、為了提高程序的性能,數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能的在自然邊界上對齊。原因是為了訪問未對齊的內(nèi)存,處理器需要進行兩次訪問,而訪問對齊的內(nèi)存,只需要一次就夠了。這種方式稱作“以空間換時間”在很多對時間復(fù)雜度有要求問題中,會采用這種方法。

  內(nèi)存對齊與自定義類型

 2、內(nèi)存對齊能夠增加程序的可移植性,因為不是所有的平臺都能隨意的訪問內(nèi)存,有些平臺只能在特定的地址處處讀取內(nèi)存。

  一般情況下內(nèi)存對齊是編譯器的事情,我們不需要考慮,但有些問題還是需要考慮的,畢竟c/c++是直接操作內(nèi)存的語言,需要了解程序在內(nèi)存中的分布和運行原理。

(二)、內(nèi)存對齊:那么如何對齊呢?

  對齊原則:數(shù)據(jù)存放的起始位置是自身大小的整數(shù)倍處。

  例:內(nèi)存從0地址處開始。

    char1個字節(jié),所以對齊后它可以存放到地址是1的倍數(shù)處。

    short2個字節(jié),所以對齊后它可以存放到地址是2的倍數(shù)處。

    int是4個字節(jié),所以對齊后它可以存放到地址是4的倍數(shù)處。

    double是8個字節(jié),所以對齊后它可以存放到地址是8的倍數(shù)處。

現(xiàn)在相信你已經(jīng)明白了內(nèi)存對齊的原則,接下來我們看看結(jié)構(gòu)體內(nèi)存對齊。

(三)、在了解結(jié)構(gòu)體內(nèi)存對齊之前先來了解幾個概念:

  1、默認(rèn)對齊數(shù):在vs下內(nèi)存對齊數(shù)默認(rèn)是8,linux是4.可以通過#program pack  ()來修改默認(rèn)對齊數(shù)。

  2、偏移:相對于起始位置的的位置。例如起始位置是2,那么2就是0偏移處,3就是1偏移處。

內(nèi)存對齊與自定義類型

  3、對齊數(shù):變量自身的大小和默認(rèn)對齊數(shù)之中的最小值。假設(shè)默認(rèn)對齊數(shù)是8,int類型的對齊數(shù)就是4.因為int大小是4,小于8

二、結(jié)構(gòu)體內(nèi)存對齊原則:

 1、結(jié)構(gòu)或聯(lián)合的數(shù)據(jù)成員,第一個成員放到0偏移的地方,以后每個數(shù)據(jù)成員都放到自身對齊數(shù)的整數(shù)倍偏移處。

 2、結(jié)構(gòu)體的大小必須是大對齊數(shù)的整數(shù)倍。

  例1:

    struct stu

    {

     char  c;      //對齊數(shù)是1

     short  b;      //對齊數(shù)是2

     double d;      //對齊數(shù)是8

     int   i;     //對齊數(shù)是4

    };

內(nèi)存對齊與自定義類型

  例2:

    struct stu

    {

     char  c;      //對齊數(shù)是1

     short  b;      //對齊數(shù)是2

     struct A

     {

       double d;     //對齊數(shù)是8

     };

     int   i;     //對齊數(shù)是4

    }s;

  嵌套結(jié)構(gòu)體的大小,其分析方法還是一樣,大對齊數(shù)是8,sizeof(s)=24。

三、自定義類型

(一)、結(jié)構(gòu)體聲明

  1、沒有標(biāo)簽,不完整的聲明。同時還定義一個變量。

          struct

          {

             charc;

              shortb;

              inti;

          }t1;

  2、有標(biāo)簽的聲明,但沒定義變量的聲明。

          struct   A

         {

           charc;

           shortb;

           inti;

         };

   //定義一個變量struct A *s1;

   //注意,在同一個程序中,同時聲明1、2兩個結(jié)構(gòu)體,則1、2兩個結(jié)構(gòu)體會被認(rèn)為是不同類型的。所以 s1=&t1是錯誤的。

  3、有標(biāo)簽的聲明,同時還定義一個變量。

          struct   A

          {

            charc;

            shortb;

            inti;

          }t3;

  4、聲明的同時對結(jié)構(gòu)體重命名為A.

           typedef  struct   A

          {

             charc;

             shortb;

             inti;

           }A;

  5、先有雞還是先有蛋

            struct B                   //無論哪個放到前面都不對

           {

              structAa;

            }s;

            structA

            {

              structBb;

             };

  如果兩個結(jié)構(gòu)體相互嵌套,則在聲明的時候需要對其中一個結(jié)構(gòu)體進行不完整的聲明。

             structA;

             struct B

               {

                  structAa;

               }s;

             structA

               {

                  structBb;

               };

(二)、結(jié)構(gòu)體的初始化:

   例如:

          typedef  struct   A

         {

            charc;

            shortb;

            inti;

         }A;

         As1 = {'c', 2 ,  4  };

(三)、結(jié)構(gòu)體的自引用:(結(jié)構(gòu)體的自引用通常會用在鏈表這種線性結(jié)構(gòu)中用到)

 1、錯誤的自引用方式,很容易理解的,結(jié)構(gòu)體里面又有結(jié)構(gòu)體,這樣一直循環(huán)下去。(從前有座廟,廟里有個老和尚,老和尚給小和尚講故事..........^v^)

           typedef struct  A

           {

               intdata;

               structAn;                     //死循環(huán)

            }A;

 2、錯誤的只引用,因為結(jié)構(gòu)體被重新命名為A是在引用之后。

           typedef struct                     //在結(jié)構(gòu)體自引用的時候標(biāo)簽不能省略。

           {

                intdata;

              An;                             //必須使用完整的結(jié)構(gòu)體名稱

           }A;

 3、正確的方式

         typedef struct  A

         {

             intdata;

             structA *n;       //用完整的結(jié)構(gòu)體名稱,聲明一個結(jié)構(gòu)體指針,

         }A;

(四)、結(jié)構(gòu)體做參數(shù)傳遞的效率:

  當(dāng)結(jié)構(gòu)體很大時,結(jié)構(gòu)體在作為參數(shù)傳遞時,我們傳遞它的地址,這樣能夠提高效率,如果你不想改變結(jié)構(gòu)體內(nèi)容,則在形參處加上const就行。

(五)、柔性數(shù)組:

  在結(jié)構(gòu)體中最后一個成員允許是未知大小的數(shù)組,這個數(shù)組成為柔性數(shù)組(柔性數(shù)組之前至少有一個成員變量)

       typedef  struct   A

        {

           inti;

           char  a[];

        }A;

  含有柔性數(shù)組的結(jié)構(gòu)體大:這樣的結(jié)構(gòu)體,它的大小不包括柔性數(shù)組,所以sizeof(A)=4;空結(jié)構(gòu)體的大小是1;

(六)、位段(位域):

 1、概念:在一個結(jié)構(gòu)體中以位為單位來指定成員所占內(nèi)存的實際大小,這種以位為單位的成員我們稱為位段,位段是一種特殊的結(jié)構(gòu)體,位段的聲明和任何普通的結(jié)構(gòu)體成員聲明類似,如下:

     Struct 位段結(jié)構(gòu)體名

       {

          Unsigned 位段名:位段長度;

          Unsigned 位段名:位段長度;

………………..

          Unsigned 位段名:位段長度;

       }位段結(jié)構(gòu)體變量名;

  但有兩個例外,首先位段成員必須聲明成int ,unsigned int, signed int,。其次,在成員的后面是一個冒號和一個整數(shù),這個整數(shù)指定該位段所占用位的個數(shù)。(實際驗證后發(fā)現(xiàn)char類型也可以,但是注意,位段中不能將int 和char 混合使用)。

 2、 位段使用時需要注意是:

    1、位段結(jié)構(gòu)體中的成員不能使用數(shù)組和指針,但結(jié)構(gòu)體變量可以使數(shù)組或者指針。

    2、因為數(shù)組和指針都是以字節(jié)為單位的,同理也不能用&獲取位段的地址。

    3、位段不支持移植。

 例1:聲明一個位段,我們先來分析一下他在計算機里面是如何存儲的(一個無符號的int是4字節(jié))。

        struct tagAAA

        {

         unsigned int a : 1;

         unsigned int b : 2;

         unsigned int c : 6;

         unsigned int d : 4;

         unsigned int e;

         }AAA_S;

內(nèi)存對齊與自定義類型

  由此我們可以明白位段的優(yōu)點,本來定義了5個成員,需要5個存儲單位,但是使用位段后只需要4個存儲空間就足夠了。

 3、優(yōu)點:

  但它的成員是一個或多個位的字段,這些不同長度的字段實際上是存儲于一個或多個×××變量中,他的優(yōu)點是能夠以較少的內(nèi)存單元存儲數(shù)據(jù)。位段可以用×××形式輸出。

例2:

   struct tagAAA

        {

         unsigned int a : 1;

         unsigned int  : 2;      //沒有聲明變量,但是卻指定位段大小,稱為占位。

         unsigned int c : 6;

         unsigned int d : 4;

         unsigned int e;       //沒有指定位段大小,默認(rèn)為自身類型的大小

         }AAA_S;

(七)、聯(lián)合

 1、聯(lián)合的聲明:

     typedefunionA

      {

        inti;

        charc;

      }A;

 2、聯(lián)合的特點:

  聯(lián)合成員之間共用同一塊空間。聯(lián)合的大小等于成員中所占內(nèi)存大變量大小。可以用來測大小端。

(八)、枚舉:

  1、聲明:

      typedefenumA

      {

          zero,

          one,

          two

      }A;

如果沒有對枚舉成員進行初始化時,則默認(rèn)枚舉成員從0開始依次遞增

 注意:

   1、在同一個程序中,不能不能聲明同名的枚舉類型

   2、在同一個程序中,不同的枚舉類型的枚舉成員不能同名。

   3、任何枚舉的大小都是4

 2、枚舉與#define 標(biāo)識符之間區(qū)別:

   1、#define 標(biāo)識符在預(yù)編譯期間進行簡單替換。枚舉類型在編譯的時候確定其值。

   2、枚舉常量可以調(diào)試,#define 標(biāo)識符不可以。

   3、枚舉一次可以定義大量的枚舉量。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

網(wǎng)站欄目:內(nèi)存對齊與自定義類型-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://bm7419.com/article34/ddpope.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、網(wǎng)站設(shè)計公司網(wǎng)站排名、全網(wǎng)營銷推廣面包屑導(dǎo)航、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)