duanlijia5864 2015-12-11 08:40
浏览 108
已采纳

如果字段顺序不同,结构的大小也将不同

package main

import (
    "fmt"
    "unsafe"
)

type A struct {
    a bool
    b int64
    c int
}

type B struct {
    b int64
    a bool
    c int
}

type C struct {
}

func main() {
    // output 24
    fmt.Println(unsafe.Sizeof(A{}))

    // output 16
    fmt.Println(unsafe.Sizeof(B{}))

    // output 0
    fmt.Println(unsafe.Sizeof(C{}))
}
  1. Struct A and B have the same fields, but if specified in different order they result in different size. why?

  2. Size of struct C is zero. How much memory is allocated by the system for a := C{}?

Thanks.

  • 写回答

1条回答 默认 最新

  • doushai4890 2015-12-11 09:19
    关注

    1. Struct sizes

    TL;DR; (Summary): Different implicit padding will be used if you reorder the fields, and the implicit padding counts towards the size of the struct.

    Note that the result depends on the target architecture; results you posted applies when GOARCH=386, but when GOARCH=amd64, sizes of both A{} and B{} will be 24 bytes.

    Address of fields of a struct must be aligned, and the address of fields of type int64 must be a multiple of 8 bytes. Spec: Package unsafe:

    Computer architectures may require memory addresses to be aligned; that is, for addresses of a variable to be a multiple of a factor, the variable's type's alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes.

    Align of int64 is 8 bytes:

    fmt.Println(unsafe.Alignof((int64(0)))) // Prints 8
    

    So in case of A since first field is bool, there is a 7-byte implicit padding after A.a so that A.b which is of type int64 can start on an address that is a multiple of 8. This (that 7-byte padding is needed exactly) is guaranteed as the struct itself is aligned to an address which is a multiple of 8, because that is the largest size of all of its fields. See: Spec: Size alignment guarantees:

    For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least 1.

    In case of B (and if GOARCH=386 which is your case) there will only be a 3-byte implicit padding after the B.a field of type bool because this field is followed by a field of type int (which has size of 4 bytes) and not int64.

    Align of int is 4 bytes if GOARCH=386, and 8 bytes if GOARCH=amd64:

    fmt.Println(unsafe.Alignof((int(0))))   // Prints 4 if GOARCH=386, and 8 if GOARCH=amd64
    

    Use unsafe.Offsetof() to find out the offsets of fields:

    // 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))
    

    Output if GOARCH=386 (try it on the Go Playground):

    24 0 8 16
    16 0 8 12
    0
    4
    

    Output if GOARCH=amd64:

    24 0 8 16
    24 0 8 16
    0
    8
    

    2. Zero size values

    Spec: Size alignment guarantees:

    A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.

    So the spec just gives a hint to use the same memory address but it's not a requirement. But current implementations follow it. That is, no memory will be allocated for values of types having a size of zero, this includes the empty struct struct{} and arrays of zero length, e.g. [0]int, or arrays whose elements has a size of zero (and with arbitrary length).

    See this example:

    a := struct{}{}
    b := struct{}{}
    c := [0]int{}
    d := [3]struct{}{}
    
    fmt.Printf("%p %p %p %p %p", &a, &b, &c, &d, &d[2])
    

    Output (try it on the Go Playground): All the addresses are the same.

    0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c
    

    For an interesting and related topic, read: Dave Cheney: Padding is hard

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Mac系统vs code使用phpstudy如何配置debug来调试php
  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)