日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

这个结构体对齐输出有意思

發(fā)布時間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 这个结构体对齐输出有意思 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這個題目是我在群里看到大家討論的,既然是討論的了,那我就拿出來說說,因為筆試面試的時候,可能就會遇到這樣的題目。

實例代碼

#include?"stdio.h" #include?"stdint.h"struct?Obj?{char?a;?//1uint32_t?b;//4uint8_t?c;//1uint64_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 請按任意鍵繼續(xù).?.?.

這里比較令我們疑惑的是,d 的大小明明是 0,為甚結(jié)構(gòu)體的大小會是 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 請按任意鍵繼續(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)

前面哪個比較簡單了,就是使用 「#」這個符號把字符串帶過來打印。下面的OFFSET 比較有意思,先是把 0 這個地址強制轉(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 請按任意鍵繼續(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 請按任意鍵繼續(xù).?.?.

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

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

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

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

這幾個原則是在 沒有 #pragma pack 的時候才起作用的,有了 #pragma pack,就按照 #pragma pack 的方式去對齊。

分析一下

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

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

為了驗證我們的想法,我們改下程序

實例代碼

#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 請按任意鍵繼續(xù).?.?.

看到?jīng)]?

看到?jīng)]?

看到?jīng)]?

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

? 推薦閱讀:

? 專輯|Linux文章匯總

? 專輯|程序人生

? 專輯|C語言

嵌入式Linux

微信掃描二維碼,關(guān)注我的公眾號?

總結(jié)

以上是生活随笔為你收集整理的这个结构体对齐输出有意思的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。