golang - 구조체의 정확한 크기 계산하기

golang의 구조체도 c/c++과 같이 패딩이 있다.

type PacketHeader struct {
	N1 int32 
	N2 int16
	N3 int64
}

위 구조체를 unsafe.Sizeof를 하면 패딩 때문에 크기가 16이 나온다.
(sizeof가 기본 기능이 아니고 unsafe 패키지를 사용해야 한다.)

구글링을 해 봐도 #pragma pack(1) 같은 것으로 1바이트 정렬하는 기능이 없다. ;;;;
그래서 구조체의 정확한 크기를 알기 위해 서는 reflect를 사용하여 아래와 같이 해야 한다.

https://play.golang.org/p/3NbjRjSRk-y

package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

func sizeof(t reflect.Type) int {
	switch t.Kind() {
	case reflect.Array:
		//fmt.Println("reflect.Array")
		if s := sizeof(t.Elem()); s >= 0 {
			return s * t.Len()
		}

	case reflect.Struct:
		//fmt.Println("reflect.Struct")
		sum := 0
		for i, n := 0, t.NumField(); i < n; i++ {
			s := sizeof(t.Field(i).Type)
			if s < 0 {
				return -1
			}
			sum += s
		}
		return sum

	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		//fmt.Println("reflect.int")
		return int(t.Size())
	case reflect.Slice:
		//fmt.Println("reflect.Slice:", sizeof(t.Elem()))
		return 0
	}

	return -1

}


type PacketHeader struct {
	N1 int32 // sizeof에서 사용할 때 int로 하면 안 됨
	N2 int16
	N3 int64
}

func main() {
	var packetHeader PacketHeader
	
	packetHeaderSize1 := unsafe.Sizeof(packetHeader)	
	fmt.Println("PacketHeader size: ", packetHeaderSize1)
	
	// sizeof 함수를 사용하면 패딩 없는 정확한 크기를 알 수 있다
	packetHeaderSize2 := sizeof(reflect.TypeOf(packetHeader))	
	fmt.Println("PacketHeader size: ", packetHeaderSize2)
}


이 글은 2019-02-08에 작성되었습니다.