1 回答

TA貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超9個贊
1. 結(jié)構(gòu)尺寸
TL; 博士; (總結(jié)):如果您對字段重新排序,將使用不同的隱式填充,并且隱式填充計(jì)入struct.
請注意,結(jié)果取決于目標(biāo)架構(gòu);適用于您發(fā)布結(jié)果時GOARCH=386,但是當(dāng)GOARCH=amd64,既大小的A{}和B{}將是24個字節(jié)。
struct的字段地址必須對齊,type字段的地址int64必須是8字節(jié)的倍數(shù)。規(guī)格: 包裝unsafe:
計(jì)算機(jī)體系結(jié)構(gòu)可能需要對齊內(nèi)存地址;也就是說,對于一個變量的地址是一個因子的倍數(shù),變量的類型的對齊方式。該函數(shù)Alignof采用一個表示任何類型變量的表達(dá)式,并以字節(jié)為單位返回變量(的類型)的對齊方式。
對齊int64是8個字節(jié):
fmt.Println(unsafe.Alignof((int64(0)))) // Prints 8
因此,如果A因?yàn)榈谝粋€字段是bool,則后面有一個 7 字節(jié)的隱式填充,A.a因此A.b類型int64可以從 8 的倍數(shù)的地址開始。這(正是需要 7 字節(jié)填充)保證為在struct本身對準(zhǔn)這是8的倍數(shù)的地址,因?yàn)檫@是所有字段的最大尺寸。請參閱:規(guī)格:尺寸對齊保證:
對于xstruct 類型的變量:unsafe.Alignof(x)是 的unsafe.Alignof(x.f)每個字段f的所有值中的最大值x,但至少是1。
在這種情況下B(如果GOARCH=386是您的情況)在B.atype 字段之后只會有一個 3 字節(jié)的隱式填充,bool因?yàn)樵撟侄魏竺媸且粋€ type 字段int(大小為 4 個字節(jié))而不是int64.
對齊int是 4 個字節(jié) if GOARCH=386,和 8 個字節(jié) if GOARCH=amd64:
fmt.Println(unsafe.Alignof((int(0)))) // Prints 4 if GOARCH=386, and 8 if GOARCH=amd64
使用unsafe.Offsetof()找出領(lǐng)域的偏移量:
// output 24
a := A{}
fmt.Println(unsafe.Sizeof(a),
unsafe.Offsetof(a.a), unsafe.Offsetof(a.b), unsafe.Offsetof(a.c))
// output 16
b := B{}
fmt.Println(unsafe.Sizeof(b),
unsafe.Offsetof(b.b), unsafe.Offsetof(b.a), unsafe.Offsetof(b.c))
// output 0
fmt.Println(unsafe.Sizeof(C{}))
var i int
fmt.Println(unsafe.Sizeof(i))
輸出 if GOARCH=386(在Go Playground上嘗試):
24 0 8 16
16 0 8 12
0
4
輸出如果GOARCH=amd64:
24 0 8 16
24 0 8 16
0
8
2. 零尺寸值
規(guī)格:尺寸對齊保證:
如果結(jié)構(gòu)或數(shù)組類型不包含大小大于零的字段(或元素),則其大小為零。兩個不同的零大小變量可能在內(nèi)存中具有相同的地址。
所以規(guī)范只是提示使用相同的內(nèi)存地址,但這不是必需的。但是當(dāng)前的實(shí)現(xiàn)遵循它。也就是說,不會為大小為零的類型值分配內(nèi)存,這包括空結(jié)構(gòu)struct{}和零長度的數(shù)組,例如[0]int,或元素大小為零(并且具有任意長度)的數(shù)組。
看這個例子:
a := struct{}{}
b := struct{}{}
c := [0]int{}
d := [3]struct{}{}
fmt.Printf("%p %p %p %p %p", &a, &b, &c, &d, &d[2])
輸出(在Go Playground上嘗試):所有地址都相同。
0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c
有關(guān)有趣且相關(guān)的主題,請閱讀:Dave Cheney:Padding is hard
- 1 回答
- 0 關(guān)注
- 182 瀏覽
添加回答
舉報