[go] unsafe包
cc7756789w · · 5555 次点击 · · 开始浏览uintptr是go的内置类型,用于指针运算,其底层基于int类型。uintptr不是指针,GC会回收uintptr类型的对象。
unsafe.Sizeof
unsafe.Sizeof函数返回的就是uintptr类型的值(表达式,即值的大小):
var p float64 = 99
fmt.Println(reflect.TypeOf(unsafe.Sizeof(p)))
fmt.Println(unsafe.Sizeof(p))
>>> uintptr
>>> 8
unsafe.Sizeof接受任意类型的值(表达式),返回其占用的字节数,在上面的例子中float64的大小是8bytes。
如果传入一个指针类型的对象会返回多少呢?
type W struct {
a byte
b int32
c int64
}
var w *W
fmt.Println(unsafe.Sizeof(w)) // 4 or 8
一般情况下,可能是4或8,因为w是指针类型uintptr,而uintptr是平台相关的,在32位系统下大小是4bytes,在64位系统下是8bytes。
要获取值类型的大小,需要对指针变量进行取值:
fmt.Println(unsafe.Sizeof(*w))
>>> 16
对齐
在上面的例子中,*w的大小为16,按照常理来说,byte占用1字节,int32占用4字节,int64占用8字节,大小应该是13才对。这是因为发生了对齐,unsafe.Alignof可以计算对齐值:
unsafe.Alignof(w.a) // type byte
unsafe.Alignof(w.b) // type int32
unsafe.Alignof(w.c) // type int64
分别是1、4、8,因为int32类型的对齐值是4bytes,必须是4的倍数,故byte类型要填充3个字节。而填充后,两者的大小和为8bytes,int64对齐值是8bytes,不需要填充,所以用unsafe.Sizeof获取到结构的大小为4+4+8=16。
反射包的对齐方法
反射包也有某些方法可用于计算对齐值:
unsafe.Alignof(w)等价于reflect.TypeOf(w).Align。
unsafe.Alignof(w.i)等价于reflect.Typeof(w.i).FieldAlign()。
结构体的对齐值
如果我们计算的是结构体的对齐值而不是某个字段或者基本类型,那么值会是多少呢?
type W struct {
a byte
b int32
c int64
}
var w *W
var w2 W
fmt.Println(unsafe.Alignof(w))
fmt.Println(unsafe.Alignof(w2))
fmt.Println(refelct.TypeOf(w).Elem().Align())
>>> 4
>>> 8
>>> 8
32位机器下,指针对象的对齐值是4,因为指针类型是uintptr。而结构体的值类型却是8bytes的对齐值,这是因为会先进行字段的对齐,字段最大的对齐值是8bytes,因此结构体值类型的对齐值也是8。
更改结构,验证一下:
type W struct {
a byte
b int32
c int32
}
var w W
fmt.Println(unsafe.Alignof(w))
>>> 4有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
uintptr是go的内置类型,用于指针运算,其底层基于int类型。uintptr不是指针,GC会回收uintptr类型的对象。
unsafe.Sizeof
unsafe.Sizeof函数返回的就是uintptr类型的值(表达式,即值的大小):
var p float64 = 99
fmt.Println(reflect.TypeOf(unsafe.Sizeof(p)))
fmt.Println(unsafe.Sizeof(p))
>>> uintptr
>>> 8
unsafe.Sizeof接受任意类型的值(表达式),返回其占用的字节数,在上面的例子中float64的大小是8bytes。
如果传入一个指针类型的对象会返回多少呢?
type W struct {
a byte
b int32
c int64
}
var w *W
fmt.Println(unsafe.Sizeof(w)) // 4 or 8
一般情况下,可能是4或8,因为w是指针类型uintptr,而uintptr是平台相关的,在32位系统下大小是4bytes,在64位系统下是8bytes。
要获取值类型的大小,需要对指针变量进行取值:
fmt.Println(unsafe.Sizeof(*w))
>>> 16
对齐
在上面的例子中,*w的大小为16,按照常理来说,byte占用1字节,int32占用4字节,int64占用8字节,大小应该是13才对。这是因为发生了对齐,unsafe.Alignof可以计算对齐值:
unsafe.Alignof(w.a) // type byte
unsafe.Alignof(w.b) // type int32
unsafe.Alignof(w.c) // type int64
分别是1、4、8,因为int32类型的对齐值是4bytes,必须是4的倍数,故byte类型要填充3个字节。而填充后,两者的大小和为8bytes,int64对齐值是8bytes,不需要填充,所以用unsafe.Sizeof获取到结构的大小为4+4+8=16。
反射包的对齐方法
反射包也有某些方法可用于计算对齐值:
unsafe.Alignof(w)等价于reflect.TypeOf(w).Align。
unsafe.Alignof(w.i)等价于reflect.Typeof(w.i).FieldAlign()。
结构体的对齐值
如果我们计算的是结构体的对齐值而不是某个字段或者基本类型,那么值会是多少呢?
type W struct {
a byte
b int32
c int64
}
var w *W
var w2 W
fmt.Println(unsafe.Alignof(w))
fmt.Println(unsafe.Alignof(w2))
fmt.Println(refelct.TypeOf(w).Elem().Align())
>>> 4
>>> 8
>>> 8
32位机器下,指针对象的对齐值是4,因为指针类型是uintptr。而结构体的值类型却是8bytes的对齐值,这是因为会先进行字段的对齐,字段最大的对齐值是8bytes,因此结构体值类型的对齐值也是8。
更改结构,验证一下:
type W struct {
a byte
b int32
c int32
}
var w W
fmt.Println(unsafe.Alignof(w))
>>> 4