go中的unsafe包及使用详解
作者:lucifer_L · 发布时间:2023-10-13 17:07:27
Unsafe code是一种绕过go类型安全和内存安全检查的Go代码。大多数情况,unsafe code是和指针相关的。但是要记住使用unsafe code有可能会损害你的程序,所以,如果你不完全确定是否需要用到unsafe code就不要使用它。
以下面的 unsafe.go 为例,看一下unsafe code的使用
package main
import (
"fmt"
"unsafe"
)
func main() {
var value int64 = 5
var p1 = &value
var p2 = (*int32)(unsafe.Pointer(p1))
这里使用了 unsafe.Pointer()
方法,这个方法能让你创造一个 int32 的 p2 指针去指向一个 int64 的 value 变量,而这个变量是使用 p1 指针去访问的,注意这种做法是有风险的。
任何go指针都可以转化为 unsafe.Pointer
指针。
unsafe.Pointer
类型的指针可以覆盖掉go的系统类型。这毫无疑问很快,但是如果不小心或者不正确使用的话就会很危险,它给了开发者更多选择去掌控数据。
unsafe.go 后面部分如下
fmt.Println("*p1: ", *p1)
fmt.Println("*p2: ", *p2)
*p1 = 5434123412312431212
fmt.Println(value)
fmt.Println("*p2: ", *p2)
*p1 = 54341234
fmt.Println(value)
fmt.Println("*p2: ", *p2)
}
你可以使用一个星号( * )来解引用一个指针
运行 unsafe.go ,会得到如下的输出
*p1: 5
*p2: 5
5434123412312431212
*p2: -930866580
54341234
*p2: 54341234
那么这个输出说明了什么呢?它告诉了我们,使用32-bit的指针无法存一个64-bit的整数型
关于unsafe包
你已经实际操作过 unsafe 包的东西了,现在来看一下为什么这个库这么特别。
首先,如果你看了 unsafe 包的源码,你可能会感到惊讶。在macOS Hight Sierra
系统上,可以使用 Homebrew 安装Go 。 unsafe 源码路径在 /usr/local/Cellar/go/1.9.1/libexec/src/unsafe/unsafe.go
下面,不包含注释,它的内容如下
$ cd /usr/local/Cellar/go/1.9.1/libexec/src/unsafe/
$ grep -v '^//' unsafe.go|grep -v '^$'
package unsafe
type ArbitraryType int
type Pointer *ArbitraryType
func Sizeof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Alignof(x ArbitraryType) uintptr
OK,其它的 unsafe 包的go代码去哪里了?答案很简单:当你import到你程序里的时候,Go编译器实现了这个unsafe库。
许多系统库,例如 runtime , syscall 和 os 会经常使用到 usafe 库
另一个usafe包的例子
我们通过一个 moreUnsafe.go
的小程序来了解unsafe库的兼容性。 moreUnsafe.go
做的事情就是使用指针来访问数组里的所有元素。
package main
import (
"fmt"
"unsafe"
)
func main() {
array := [...]int{0, 1, -2, 3, 4}
pointer := &array[0]
fmt.Print(*pointer, " ")
memoryAddress := uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
for i := 0; i < len(array)-1; i++ {
pointer = (*int)(unsafe.Pointer(memoryAddress))
fmt.Print(*pointer, " ")
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
}
首先, pointer 变量指向 array[0] 的地址, array[0] 是整型数组的第一个元素。接下来指向整数值的 pointer 变量会传入 unsafe.Pointer()
方法,然后传入 uintptr 。最后结果存到了 memoryAddress
里。
unsafe.Sizeof(array[0])
是为了去访问下一个数组元素,这个值是每个元素占的内存大小。每次for循环遍历,都会把这个值加到 memoryAddress 上,这样就能获取到下一个数组元素的地址。 *pointer 的*符号对指针进行解引用,然后返回了所存的整数值。
后面部分代码如下:
fmt.Println()
pointer = (*int)(unsafe.Pointer(memoryAddress))
fmt.Print("One more: ", *pointer, " ")
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
fmt.Println()
}
这里,我们尝试使用指针和内存地址去访问一个不存在的数组元素。由于使用 unsafe 包,Go编译器不会捕捉到这样的逻辑错误,因而会产生一些不可预料的事情。
执行 moreUnsafe.go ,会产生如下的输出:
$ go run moreUnsafe.go
0 1 -2 3 4
One more: 824634191624
现在,你使用指针访问了Go数组里的所有元素。但是,这里真正的问题是,当你尝试访问无效的数组元素,程序并不会出错而是会返回一个随机的数字。
总结
unsafe的功能很强大,它可以把任意指针转换为 unsafe.Pointer
指针,同时给了开发人员更多操作数据的手段。但是相对的,如果使用不当,则会造成不可预料的错误,这也是为什么这个包的名字被称作 unsafe 的原因,所以在你不确定是否该使用 unsafe 操作的时候,尽量不要使用它。
以上所述是小编给大家介绍的go中的unsafe包,希望对大家有所帮助
来源:https://studygolang.com/articles/22265
猜你喜欢
- 给定一篇英语文章,要求统计出所有单词的个数,并按一定次序输出。思路是利用go语言的map类型,以每个单词作为关键字存储数量信息,代码实现如下
- Hello every, 我是Sunrise_Chen,有人知道我吗?好久没来这里了,以前偶尔会来这里潜水今天心情很好,写了几个特效果。特效
- strConnString = "driver={MySQL ODBC 3.51 
- Q: 不知xml和html有什么区别?它们不同在哪? A: 关于XML和HTML区别请参考: http://www.w3c.org/Mark
- 说绘画语言,西方的油画是人类视觉语言里怎么也不能忽略的浓烈一笔。14~15世纪,蛋彩画——油画前身的发明,绘画可以使用均匀过渡的色彩渐变,并
- 本文是关于人物角色的一些简单介绍,感谢瑶芝同学提供的大力帮助! 人物角色(Personas)作为一种技术
- W3C发布了WCAG 2.0提案(Web Content Accessibility Guidelines 网页内容无障碍指南),大概为了实
- 继Go 1.18支持泛型后,Go 将在下个版本中支持pdqsort排序算法再次引起了开发者们的热切讨论。目前,Go仓库的最新commit中提
- 一、框架菜单1.1 common模块1.2 其他二、Excel接口测试案例编写三、读取Excel测试封装(核心封装)excel_utils.
- asp代码 如下:读取注册表信息使用了对象WScript.Shell<%Dim strPath strP
- 突然想到了之前一直没留意的for循环中开goroutine的执行顺序问题,就找了段代码试了试,试了几次后发现几个有意思的地方,我暂时没有精力
- python3字符串操作 x = 'abc' y = 'defgh' print(x + y)
- 很早以前就说过,IE8的标准模式已经不再支持滤镜了,不过IE仍然留了一条后路,你可以在CSS中这样写滤镜:-ms-filter
- 一、无组件上传的原理我还是一点一点用一个实例来说明的吧,客户端HTML如下。要浏览上传附件,我们通过<input type="
- 返回页面的类容,weburl为页面urlFunction GetBytes(weburl) '创建
- 今天再为大家提供一种方法:不需要安装Excel也可以导入到我们的SQL Server数据库。首先用SQL Server自身的数据转换功能把E
- 简介Go的标准包Container中包含了常用的容器类型,包括conatiner/list,container/heap,container
- 在 玉伯 的文章 《一道大题目,嘿嘿》 中有这样一段代码:[] == ![]也许很多同学迷惑:咦,这个如何转换呢?首先,我们了解下逻辑 NO
- 前边看到有人发了个层打开效果,总感觉不是很理想 个人认为:-),如果那个层放到固定的容器里面估计就会出现问题的。今天自己来写个,可以支持 在
- 写在前面的话:此篇还是asp相关的,相信玩ASP的都有这个感觉,当数据有5万多条时-------just like音乐网,要调用最新的10条