func main() {
type A1 struct {
a bool
b int16
c int
}
var a1 A1
fmt.Println(unsafe.Sizeof(a1), unsafe.Offsetof(a1.a), unsafe.Offsetof(a1.b), unsafe.Offsetof(a1.c))
}
64位下,输出“16 0 2 8”
32位下,输出“8 0 2 4”
简单改一下上面的代码,看看反汇编的结果
func main() {
type A1 struct {
a bool
b int16
c int
}
var a1 A1
a1.b = 12
}
反汇编代码go tool compile -N -l -S main.go
TEXT main.main(SB), NOSPLIT|ABIInternal, $24-0
PUSHQ BP
MOVQ SP, BP
SUBQ $16, SP
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
MOVB $0, main.a1(SP)
MOVW $0, main.a1+2(SP)
MOVQ $0, main.a1+8(SP)
MOVW $12, main.a1+2(SP)
ADDQ $16, SP
POPQ BP
RET
C语言的结构体上按“字”(WORD)对齐的,而Go语言中是按类型的整数倍对齐。举例来说
64位下,输出“16 0 2 8” 32位下,输出“8 0 2 4”
简单改一下上面的代码,看看反汇编的结果
反汇编代码
go tool compile -N -l -S main.go
代码
SUBQ $16, SP
,可以看到,a1是在栈上生成的 后面会对每个结构体字段用0初始化Plan9汇编提供小于字对MOV指令。可以确认的是,结构体中的“空洞”并没初始化。
把
var a1 A1
改为var a1 = new(A1)
,发现还是在栈上生成的(逃逸分析)这里指针多占用了一个字。
我们打破逃逸分析,试一下
反汇编结果
现在是调
CALL runtime.newobject(SB)
分配内存了