unsafe 库使用小结
2015-11-18 15:29
148 查看
unsafe 库让 golang 可以像 C 语言一样操作计算机内存,但这并不是 golang 推荐使用的,能不用尽量不用,就像它的名字所表达的一样,它绕过了golang的内存安全原则,是不安全的,容易使你的程序出现莫名其妙的问题,不利于程序的扩展与维护。
unsafe 包的内容不多,下面就它提供的函数进行说明
结果:
这里以0x0作为基准内存地址。打印出来总共占用40个字节。t.t1 为 char,对齐值为 1,0x0 % 1 == 0,从0x0开始,占用一个字节;t.t2 为 int32,对齐值为 4,0x4 % 4 == 0,从 0x4 开始,占用 4 个字节;t.t3 为 int64,对齐值为 8,0x8 % 8 == 0,从 0x8 开始,占用 8 个字节;t.t4 为 string,对齐值为 8,0x16 % 8 == 0,从 0x16 开始, 占用 16 个字节(string 内部实现是一个结构体,包含一个字节类型指针和一个整型的长度值);t.t5 为 bool,对齐值为 1,0x32 % 8 == 0,从 0x32 开始,占用 1 个字节。从上面分析,可以知道 t 的对齐值为 8,最后 bool 之后会补齐到 8 的倍数,故总共是 40 个字节。
结果
分析如上 unsafe.Sizeof 中说明。
这里仍然取上面定义的结构体 T 进行说明。
借助于 unsafe.Pointer,我们实现了像 C 语言中的指针偏移操作。可以看出,这种不安全的操作使得我们可以在任何地方直接访问结构体中未公开的成员,只要能得到这个结构体变量的地址。
unsafe 包的内容不多,下面就它提供的函数进行说明
unsafe.Alignof
获取变量的对齐值,除 int、uintptr 这些依赖CPU位数的类型,基本类型的对齐值都是固定的。 结构体的对齐值取他的成员对齐值的最大值。可以通过下面示例打印出相应的对齐值(实验机器是64位机器)。e.g. fmt.Println(unsafe.Alignof(byte(0))) fmt.Println(unsafe.Alignof(int8(0))) fmt.Println(unsafe.Alignof(uint8(0))) fmt.Println(unsafe.Alignof(int16(0))) fmt.Println(unsafe.Alignof(uint16(0))) fmt.Println(unsafe.Alignof(int32(0))) fmt.Println(unsafe.Alignof(uint32(0))) fmt.Println(unsafe.Alignof(int64(0))) fmt.Println(unsafe.Alignof(uint64(0))) fmt.Println(unsafe.Alignof(uintptr(0))) fmt.Println(unsafe.Alignof(float32(0))) fmt.Println(unsafe.Alignof(float64(0))) //fmt.Println(unsafe.Alignof(complex(0, 0))) fmt.Println(unsafe.Alignof(complex64(0))) fmt.Println(unsafe.Alignof(complex128(0))) fmt.Println(unsafe.Alignof("")) fmt.Println(unsafe.Alignof(new(int))) fmt.Println(unsafe.Alignof(struct { f float32 ff float64 }{})) fmt.Println(unsafe.Alignof(make(chan bool, 10))) fmt.Println(unsafe.Alignof(make([]int, 10))) fmt.Println(unsafe.Alignof(make(map[string]string, 10)))
类型 | 对齐值 |
---|---|
byte | 1 |
bool | 1 |
int8 | 1 |
uint8 | 1 |
int32 | 4 |
int64 | 8 |
uint32 | 4 |
uint64 | 8 |
uintptr | 8 |
float32 | 8 |
float64 | 8 |
complex64 | 8 |
complex128 | 8 |
chan | 8 |
slice | 8 |
map | 8 |
struct | it depends on the max align among its members |
unsafe.Sizeof
查看变量所占字节数。以下面例子简要说明。type T struct { t1 byte t2 int32 t3 int64 t4 string t5 bool } func main() { t := &T{1, 2, 3, "", true} fmt.Println(unsafe.Sizeof(*t)) fmt.Println(unsafe.Sizeof(t.t1)) fmt.Println(unsafe.Sizeof(t.t2)) fmt.Println(unsafe.Sizeof(t.t3)) fmt.Println(unsafe.Sizeof(t.t4)) fmt.Println(unsafe.Sizeof(t.t5)) }
结果:
40 1 4 8 16 1
这里以0x0作为基准内存地址。打印出来总共占用40个字节。t.t1 为 char,对齐值为 1,0x0 % 1 == 0,从0x0开始,占用一个字节;t.t2 为 int32,对齐值为 4,0x4 % 4 == 0,从 0x4 开始,占用 4 个字节;t.t3 为 int64,对齐值为 8,0x8 % 8 == 0,从 0x8 开始,占用 8 个字节;t.t4 为 string,对齐值为 8,0x16 % 8 == 0,从 0x16 开始, 占用 16 个字节(string 内部实现是一个结构体,包含一个字节类型指针和一个整型的长度值);t.t5 为 bool,对齐值为 1,0x32 % 8 == 0,从 0x32 开始,占用 1 个字节。从上面分析,可以知道 t 的对齐值为 8,最后 bool 之后会补齐到 8 的倍数,故总共是 40 个字节。
unsafe.Offsetof
查看结构体成员的偏移字节数。以上面这个例子中结构体 T 为例。func main() { t := &T{1, 2, 3, "", true} fmt.Println(unsafe.Offsetof(t.t1)) fmt.Println(unsafe.Offsetof(t.t2)) fmt.Println(unsafe.Offsetof(t.t3)) fmt.Println(unsafe.Offsetof(t.t4)) fmt.Println(unsafe.Offsetof(t.t5)) }
结果
0 4 8 16 32
分析如上 unsafe.Sizeof 中说明。
unsafe.Pointer
这个主要用于不同指针类型之间进行强制类型转换。它是一个中介者,不同指针类型不能直接进行转换,只能通过它中转一下。但是它还无法直接进行指针运算,必须将其转化成 uintptr 类型才能进行指针的运算,uintptr 与 unsafe.Pointer 之间可以相互转换。这里仍然取上面定义的结构体 T 进行说明。
t := &T{1, 2, 3, "this is a example", true} ptr := unsafe.Pointer(t) t1 := (*byte)(ptr) *t1 = 4 t2 := (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) + unsafe.Offsetof(t.t2))) *t2 = 99 fmt.Println(t) t3 := (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) + unsafe.Offsetof(t.t3))) *t3 = 333 fmt.Println(t)
借助于 unsafe.Pointer,我们实现了像 C 语言中的指针偏移操作。可以看出,这种不安全的操作使得我们可以在任何地方直接访问结构体中未公开的成员,只要能得到这个结构体变量的地址。
相关文章推荐
- 学习css3过渡效果,可以实现很好玩的东西,无需js
- JScrollPane控件中添加其他控件的问题&&JScrollPane设置滚动条&&调整滚动速度
- CSS3规范语言 适合新手
- jQuery中的.bind()、.live()和.delegate()之间区别分析
- css定位机制
- web -- CSS3
- 解决php的It is not safe to rely on the system’s timezone settings的问题
- 判断浏览器对css和html的支持
- jquery table 操作
- JScrollPane控件中添加其他控件的问题&&JScrollPane设置滚动条&&调整滚动速度
- JS中设置backgroun-position不成功的问题
- HTML与CSS入门——第七章 使用表格显示信息
- HTML学习4:常用标签之框架标签
- Head First HTML CSS XHTML笔记
- js中使用jstl中得到的值
- JSTL详解
- 共享日常收集JS正则表达式(JavaScript regular expression)
- flexigrid使用记录
- js动态绑定事件
- JavaScript中的this