关闭

unsafe 库使用小结

标签: golang
2269人阅读 评论(1) 收藏 举报
分类:

unsafe 库让 golang 可以像 C 语言一样操作计算机内存,但这并不是 golang 推荐使用的,能不用尽量不用,就像它的名字所表达的一样,它绕过了golang的内存安全原则,是不安全的,容易使你的程序出现莫名其妙的问题,不利于程序的扩展与维护。

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 语言中的指针偏移操作。可以看出,这种不安全的操作使得我们可以在任何地方直接访问结构体中未公开的成员,只要能得到这个结构体变量的地址。

2
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Golang中unsafe.Sizeof()的问题

*今天看到一段代码感觉很奇怪。。。*
  • kongkongkkk
  • kongkongkkk
  • 2017-11-22 20:15
  • 288

Go语言 unsafe的妙用

unsafe.Pointer其实就是类似C的void *,在golang中是用于各种指针相互转换的桥梁。uintptr是golang的内置类型,是能存储指针的整型,uintptr的底层类型是int,它...
  • abv123456789
  • abv123456789
  • 2014-04-20 09:57
  • 2935

golang中unsafe包浅析

unsafe内容介绍func Alignof(x ArbitraryType) uintptr func Offsetof(x ArbitraryType) uintptr func Sizeof(x...
  • hzwy23
  • hzwy23
  • 2017-03-09 00:13
  • 601

Golang unsafe的妙用

unsafe.Pointer其实就是类似C的void *,在golang中是用于各种指针相互转换的桥梁。uintptr是golang的内置类型,是能存储指针的整型,uintptr的底层类型是int,它...
  • wangkai_123456
  • wangkai_123456
  • 2017-05-21 22:46
  • 392

GoLang 强制类型转换:unsafe.Pointer

注意此种转换只适合简单类型,对于有对象描述的类型是完全不适用的,鸡肋啊 ps:补充另外一种用法,这次就不鸡肋了 Go语言是个强类型语言。也就是说Go对类型要求严格,不同类型不能进行赋值操作。指...
  • Creak_Phone
  • Creak_Phone
  • 2014-01-02 17:53
  • 2657

C#中unsafe的使用

1. unsafe在C#程序中的使用场合:1)实时应用,采用指针来提高性能;2)引用非.net DLL提供的如C++编写的外部函数,需要指针来传递该函数;3)调试,用以检测程序在运行过程中的内存使用状...
  • wolf_baby
  • wolf_baby
  • 2006-05-26 10:07
  • 15266

Unsafe

来源:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/ Java是一门安全的编程语言,并且防范程序员犯大量的愚...
  • JJYWEN
  • JJYWEN
  • 2016-04-15 23:25
  • 4680

Unsafe 源码解析

/** * This class should provide access to low-level operations and its * use should be limited to ...
  • Alex19881006
  • Alex19881006
  • 2014-04-28 15:39
  • 1749

JAVA并发编程学习笔记之Unsafe类

java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,主要提供了以下功能: 1、通过Unsafe类可以分配内存,可以释放内存; 类中提供的3个本地方法a...
  • aesop_wubo
  • aesop_wubo
  • 2012-05-05 15:30
  • 25384

使用sun.misc.Unsafe及反射对内存进行内省(introspection)

对于一个有经验的JAVA程序员来说,了解到由一个或者其它的JAVA对象占用了多少内存,这将会非常有用。你可能已经听说过我们所生活的世界,存储容量将不再是一个问题,这个对于你的文本编辑器来说可能是对的(...
  • fenglibing
  • fenglibing
  • 2013-12-04 21:25
  • 6822
    个人资料
    • 访问:67697次
    • 积分:1581
    • 等级:
    • 排名:千里之外
    • 原创:65篇
    • 转载:0篇
    • 译文:28篇
    • 评论:5条
    文章分类
    最新评论