<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          這個(gè)結(jié)構(gòu)體對(duì)齊輸出有意思

          共 4119字,需瀏覽 9分鐘

           ·

          2020-08-03 08:04

          這個(gè)題目是我在群里看到大家討論的,既然是討論的了,那我就拿出來(lái)說(shuō)說(shuō),因?yàn)楣P試面試的時(shí)候,可能就會(huì)遇到這樣的題目。

          實(shí)例代碼

          #include?"stdio.h"
          #include?"stdint.h"

          struct?Obj?{
          ????char?a;?//1
          ????uint32_t?b;//4
          ????uint8_t?c;//1
          ????uint64_t?d[0];//8
          };

          int?main()
          {
          ?struct?Obj?Op;

          ?printf("%d?%d\n",sizeof(Op),sizeof(Op.d));
          ?return?(0);
          }?

          程序輸出

          16?0

          --------------------------------
          Process?exited?after?0.03048?seconds?with?return?value?0
          請(qǐng)按任意鍵繼續(xù).?.?.

          這里比較令我們疑惑的是,d 的大小明明是 0,為甚結(jié)構(gòu)體的大小會(huì)是 16呢?

          調(diào)戲一下

          看看下面代碼的輸出

          #include?"stdio.h"
          #include?"stdint.h"

          #define?PRINT_D(intValue)?????printf(#intValue"?is?%d\n",?(intValue));
          #define?OFFSET(struct,member)??((char?*)&((struct?*)0)->member?-?(char?*)0)

          #pragma?pack(1)

          struct?Obj?{
          ????char?a;?
          ????uint32_t?b;
          ????uint8_t?c;
          ????uint64_t?d[0];
          };

          int?main()
          {
          ?struct?Obj?Op;
          ?PRINT_D(OFFSET(struct?Obj,a));?
          ?PRINT_D(OFFSET(struct?Obj,b));?
          ?PRINT_D(OFFSET(struct?Obj,c));?
          ?PRINT_D(OFFSET(struct?Obj,d));?
          ?printf("%d?%d\n",sizeof(Op),sizeof(Op.d));
          ?return?(0);
          }?

          程序輸出

          OFFSET(struct?Obj,a)?is?0
          OFFSET(struct?Obj,b)?is?1
          OFFSET(struct?Obj,c)?is?5
          OFFSET(struct?Obj,d)?is?6
          6?0

          --------------------------------
          Process?exited?after?0.0108?seconds?with?return?value?0
          請(qǐng)按任意鍵繼續(xù).?.?.

          這里的輸出剛好是我們的結(jié)構(gòu)體里內(nèi)容的大小

          解釋下這段調(diào)試代碼的作用

          #define?PRINT_D(intValue)?????printf(#intValue"?is?%d\n",?(intValue));
          #define?OFFSET(struct,member)??((char?*)&((struct?*)0)->member?-?(char?*)0)

          前面哪個(gè)比較簡(jiǎn)單了,就是使用 「#」這個(gè)符號(hào)把字符串帶過(guò)來(lái)打印。下面的OFFSET 比較有意思,先是把 0 這個(gè)地址強(qiáng)制轉(zhuǎn)換成我們需要的strunct ,然后呢,再讀取地址減去0地址,這樣就可以得出它的偏移大小了。

          調(diào)戲一下2

          我們改一下代碼

          #include?"stdio.h"
          #include?"stdint.h"

          #define?PRINT_D(intValue)?????printf(#intValue"?is?%d\n",?(intValue));
          #define?OFFSET(struct,member)??((char?*)&((struct?*)0)->member?-?(char?*)0)

          #pragma?pack(4)

          struct?Obj?{
          ????char?a;?
          ????uint32_t?b;
          ????uint8_t?c;
          ????uint64_t?d[0];
          };

          int?main()
          {
          ?struct?Obj?Op;
          ?PRINT_D(OFFSET(struct?Obj,a));?
          ?PRINT_D(OFFSET(struct?Obj,b));?
          ?PRINT_D(OFFSET(struct?Obj,c));?
          ?PRINT_D(OFFSET(struct?Obj,d));?
          ?printf("%d?%d\n",sizeof(Op),sizeof(Op.d));
          ?return?(0);
          }?

          程序輸出

          OFFSET(struct?Obj,a)?is?0
          OFFSET(struct?Obj,b)?is?4
          OFFSET(struct?Obj,c)?is?8
          OFFSET(struct?Obj,d)?is?12
          12?0

          --------------------------------
          Process?exited?after?0.01165?seconds?with?return?value?0
          請(qǐng)按任意鍵繼續(xù).?.?.

          調(diào)戲代碼3

          #include?"stdio.h"
          #include?"stdint.h"

          #define?PRINT_D(intValue)?????printf(#intValue"?is?%d\n",?(intValue));
          #define?OFFSET(struct,member)??((char?*)&((struct?*)0)->member?-?(char?*)0)

          #pragma?pack(8)

          struct?Obj?{
          ????char?a;?
          ????uint32_t?b;
          ????uint8_t?c;
          ????uint64_t?d[0];
          };

          int?main()
          {
          ?struct?Obj?Op;
          ?PRINT_D(OFFSET(struct?Obj,a));?
          ?PRINT_D(OFFSET(struct?Obj,b));?
          ?PRINT_D(OFFSET(struct?Obj,c));?
          ?PRINT_D(OFFSET(struct?Obj,d));?
          ?printf("%d?%d\n",sizeof(Op),sizeof(Op.d));
          ?return?(0);
          }?

          程序輸出

          OFFSET(struct?Obj,a)?is?0
          OFFSET(struct?Obj,b)?is?4
          OFFSET(struct?Obj,c)?is?8
          OFFSET(struct?Obj,d)?is?16
          16?0

          --------------------------------
          Process?exited?after?0.01219?seconds?with?return?value?0
          請(qǐng)按任意鍵繼續(xù).?.?.

          結(jié)構(gòu)體對(duì)齊大小的方式,這個(gè)背下,不背下就存下

          原則A:struct或者union的成員,第一個(gè)成員在偏移0的位置,之后的每個(gè)成員的起始位置必須是當(dāng)前成員大小的整數(shù)倍;

          原則B:如果結(jié)構(gòu)體A含有結(jié)構(gòu)體成員B,那么B的起始位置必須是B中最大元素大小整數(shù)倍地址;

          原則C:結(jié)構(gòu)體的總大小,必須是內(nèi)部最大成員的整數(shù)倍;

          這幾個(gè)原則是在 沒(méi)有 #pragma pack 的時(shí)候才起作用的,有了 #pragma pack,就按照 #pragma pack 的方式去對(duì)齊。

          分析一下

          基于上面的實(shí)驗(yàn)和理論,我們可以知道,這個(gè)筆試題的輸出結(jié)果是因?yàn)?uint64_t d[] 這個(gè)搞鬼了,就是因?yàn)檫@個(gè)搞鬼了,我們結(jié)構(gòu)體的最終大小才是 16。因?yàn)?uint64_t d 是 8個(gè)字節(jié),這樣結(jié)構(gòu)體就是以 8 字節(jié)的方式對(duì)齊了。

          雖然d 的不占用內(nèi)存的,但是這個(gè)家伙的存在讓結(jié)構(gòu)體的對(duì)齊方式產(chǎn)生了改變,就是這么神奇。

          為了驗(yàn)證我們的想法,我們改下程序

          實(shí)例代碼

          #include?"stdio.h"
          #include?"stdint.h"

          #define?PRINT_D(intValue)?????printf(#intValue"?is?%d\n",?(intValue));
          #define?OFFSET(struct,member)??((char?*)&((struct?*)0)->member?-?(char?*)0)

          struct?Obj?{
          ????char?a;?
          ????uint32_t?b;
          ????uint8_t?c;
          ????uint32_t?d[0];
          };

          int?main()
          {
          ?struct?Obj?Op;
          ?PRINT_D(OFFSET(struct?Obj,a));?
          ?PRINT_D(OFFSET(struct?Obj,b));?
          ?PRINT_D(OFFSET(struct?Obj,c));?
          ?PRINT_D(OFFSET(struct?Obj,d));?
          ?printf("%d?%d\n",sizeof(Op),sizeof(Op.d));
          ?return?(0);
          }?

          程序輸出

          OFFSET(struct?Obj,a)?is?0
          OFFSET(struct?Obj,b)?is?4
          OFFSET(struct?Obj,c)?is?8
          OFFSET(struct?Obj,d)?is?12
          12?0

          --------------------------------
          Process?exited?after?0.01002?seconds?with?return?value?0
          請(qǐng)按任意鍵繼續(xù).?.?.

          看到?jīng)]?

          看到?jīng)]?

          看到?jīng)]?

          這樣之后,程序的輸出就是 12 了,也就是說(shuō),現(xiàn)在的程序是按照 4字節(jié)對(duì)齊方式來(lái)對(duì)齊了。


          ? 推薦閱讀:
          ? 專輯|Linux文章匯總
          ? 專輯|程序人生
          ? 專輯|C語(yǔ)言


          嵌入式Linux
          微信掃描二維碼,關(guān)注我的公眾號(hào)?
          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费亚洲在线 | 豆花视频在线观看国产豆花 | 免费日本aa视频 | 国产1234在线观看 | 97超碰人人模人人人爽人人爱 |