您的位置:首页 > Web前端

[go] unsafe包

2016-04-25 12:48 369 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: