看板 C_and_CPP 關於我們 聯絡資訊
拋磚引玉。 事先丟原 po 水球過, 大概知道想知道、想要的是什麼, < 至少應該不會再被說丟了一堆他知道的東西搪塞、落跑才對 > 做個整理一下。 再次強調的是,padding 問題是真的 implement by compiler, 我只能說這些規則目前在大多 compiler 下是這麼做的。 ※ 引述《rifiz (薩哈拉雅)》之銘言: 延續 case 28 之 struct union A { struct { unsinged int p1:4; unsigned int p2:2; unsigned int p3:4; unsigned int p4:6; } unsigned int kk; } union A obj = {3,2,4,5}; 首先這是第一個 undefined ,目前實際上我也沒看過別人這麼做, 對 union 事實上沒辦法進行初始予以賦值。所以只能這麼做。 union A obj ; obj.p1=3 , obj.p2=2 , obj.p3=4 , obj.p4=5; 忘了從哪版開始可這麼做 union A obj = {.p1=3 , .p2=2 , .p3=4 , .p4=5}; 再來是 struct padding 一些整理,有誤更正。 1. 成員均屬同型資料型態(depends on compiler) 成員均屬同型資料型態時大多 compiler 做法是不去 padding struct m1{ char c1, c2, c3;} sizeof(struct m1) = 3 2. 成員不同資料型態時 (depends on compiler) struct m1{ struct m2{ struct m3{ char a; char a; int a; int b; char b; char b; char c; int c; char c; }; }; }; m1 : (a,b) offset 3bytes , (b,c) offset 0byte , (c,end) offset 3bytes , total = 1 + 3 + 4 + 0 + 1 + 3 = 12   m2 : (a,b) offset 0byte (同資料態型不 padding), (b,c) offset 2bytes (2 對齊 4 ) (c,end) offset 0byte total = 1 + 1 + 2 + 4 = 8 m3 : (a,b) offset 0byte (b,c) offset 0byte (c,end) offset 2byte (2 對齊 4 ) total = 4 + 0 + 1 + 0 + 1 + 2 = 8 < 所以流傳讓 struct 變小就是將同質資料型態寫在一起,  並以大到小或小到大方式進行宣告。> 強調了,所有的 padding 還是依 compiler 為主。 像下面這個我擠破頭也不知道為什麼。 struct Student{ int ID; // 4 char name[200]; // 200 float score; // 4 double l; // 8 char *p; // 4 };  上述理應不會 padding, 結果應該是 220, 但莫名的被 compiler 後, padding 後結果變成 224, 而且 offset 在 char *p 之後。 compiler 它認為這麼做是對於速度最快的,我是算不出來為什麼, 因整個結構體也被 padding 到 4 的倍數了, 不過 vc 裡下了這個指令後一切就正常了。 #pragma pack(push,4) struct s{ int ID; // 4 char name[200]; // 200 float score; // 4 double l; // 8 char *p; // 4 }; #pragma pack(pop) gcc 也有相對應的指令, __attribution__((packet)) 之類的, 它讓 coder 對於 padding 上的猜測會更加準確。 3. bit-field padding bit-field 也是 depends on compiler 嚴重的一項問題。 struct s { unsigned a:1; unsigned b:2; }; // size = 4 , 其它 28 bits 不用 struct s1{ unsigned a:1; int b:1; }; // size = 4 , a 與 b 資料型態長度相同,用在同一 byte 裡 來講一個 ieee754 較常犯錯的例子。 struct _754 { unsigned int mantissa : 23; unsigned char exponment : 8 ; unsigned char sign : 1 ; }; 看起來是 32 bits, 實際上被 padding 成 64 bits 原因在於 unsigned int 到 unsigned char 時,資料型態大小不同, 所以 exponment / mantissa 不會被緊接著放,修正方式是將 unsigned char 全改成 unsigned int 即可。 關於 bit_field 個人習慣是全用同一種、最長的資料型態, 如果真的有必要跳的話也可以自己搞, padding 不可預測情況也較低, 也少用 unsigned int : 0 這種東西,寧可自己事先算好。 ------- 我一定要強調,在標準底下,上面這些 「甘哪塞」, 它只是大多 compiler < 其實也才驗證過兩個而已 > 這麼搞, 若真有如  VictorTom 之需求, 我想用 compiler 特定之 #pragma pack(push,1) 較佳, 當然這也是 speed - space trade-off 問題。 最後若要查某個變數是否 padding 、 padding 幾 bytes , 參考這篇  http://ppt.cc/HEX- 裡面的 section 3-10 唯 bit-field 之成員由於無法使用取址運算子(&),故沒辦法查。 ------- 拋磚引玉而已,參考一下,有誤或有其他心得版友也不吝提出,感激不盡 :) -- 「自從我學了 C# , 人都變聰明 , 考試都考一百分」 「自從我學了 VB , 皮膚都變好 , 人也變漂亮了 」 「自從我學了 Java , 明顯變壯 , 個子也變高了 」 「自從我學了 C++ , 內分泌失調 , 頭都禿了... 」 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 180.177.76.161
x000032001: 06/18 01:51
hilorrk:union用initializer list時會初始化the first named 06/18 02:41
hilorrk:member...(ISO 9899 6.7.8) 應該不是全都無法初始化吧? 06/18 02:42
hilorrk:至於 designated initializer 則是C99的標準 06/18 02:44
EdisonX:疑!! 那該說是手邊 compiler 不支援 init. list 嗎 ? 06/18 02:51
EdisonX:< 我和原po改用逐一assigned,觀查都屬正常 > 06/18 02:53
EdisonX:感謝 h 大補充 :) 06/18 02:53
VictorTom:220/224,應該是為了讓double那個也確保能align到:) 06/18 09:12
diabloevagto:在padding檢查實際offset多少,是看參數的addr嗎? 06/18 10:34
littleshan:C99 提供 offsetof() 06/18 13:12
EdisonX:嗯,c99提供offsetof,我於連結中提的paddingof也是類似原理 06/18 15:13
EdisonX:是將struct addr head先定到NULL,其它的再依序相減。 06/18 15:15
EdisonX:< 補上,謝謝 VictorTom 大的見解 :) > 06/18 15:16
rifiz:感恩阿~~慢慢研究中 ORZ... 06/19 16:40
Favonia:我先提個東西好了,C11 才有 anonymous struct/union 06/21 10:26