为什么这两个结构在内存中有不同的大小?

时间:2018-02-12 18:32:45

标签: go struct compiler-optimization

假设我有这两个结构:

package main

import (
    "fmt"
    "unsafe"
)

type A struct {
    int8
    int16
    bool
}

type B struct {
    int8
    bool
    int16
}

func main() {
    fmt.Println(unsafe.Sizeof(A{}), unsafe.Sizeof(B{})) // 6 4
}

A的大小为6个字节。但是,B的大小是4个字节 我认为它与它们在内存中的布局有关,但我不确定我是否理解为什么它的行为如此。
不是编译器可以检测和优化的东西吗? (重新排列字段顺序)

Why are RECTs endpoint-exclusive?

1 个答案:

答案 0 :(得分:9)

由于对齐而填充。

  

The Go Programming Language Specification

     

Size and alignment guarantees

     

对于数字类型,保证以下尺寸:

type                                 size in bytes

byte, uint8, int8                     1
uint16, int16                         2
uint32, int32, float32                4
uint64, int64, float64, complex64     8
complex128                           16
     

保证以下最小对齐属性:

     
      
  • 对于任何类型的变量x:unsafe.Alignof(x)至少为1.

  •   
  • 对于结构类型的变量x:unsafe.Alignof(x)是x的每个字段f的所有值unsafe.Alignof(x.f)中最大的,但至少是   1。

  •   
  • 对于数组类型的变量x:unsafe.Alignof(x)与数组元素类型的变量的对齐方式相同。
  •   
     

如果结构或数组类型不包含任何字段(或   元素,分别),大小大于零。二   不同的零大小变量在内存中可能具有相同的地址。

例如,

package main

import (
    "fmt"
    "unsafe"
)

type A struct {
    x int8
    y int16
    z bool
}

type B struct {
    x int8
    y bool
    z int16
}

func main() {
    var a A
    fmt.Println("A:")
    fmt.Println("Size:   ", unsafe.Sizeof(a))
    fmt.Printf("Address: %p %p %p\n", &a.x, &a.y, &a.z)
    fmt.Printf("Offset:  %d %d %d\n", unsafe.Offsetof(a.x), unsafe.Offsetof(a.y), unsafe.Offsetof(a.z))
    fmt.Println()
    var b B
    fmt.Println("B:")
    fmt.Println("Size:   ", unsafe.Sizeof(b))
    fmt.Printf("Address: %p %p %p\n", &b.x, &b.y, &b.z)
    fmt.Printf("Offset:  %d %d %d\n", unsafe.Offsetof(b.x), unsafe.Offsetof(b.y), unsafe.Offsetof(b.z))
}

游乐场:https://play.golang.org/p/_8yDMungDg0

输出:

A:
Size:    6
Address: 0x10410020 0x10410022 0x10410024
Offset:  0 2 4

B:
Size:    4
Address: 0x10410040 0x10410041 0x10410042
Offset:  0 1 2

您可能正在使用其他语言匹配外部struct。您可以告诉编译器您想要什么。编译器没有猜测。