Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >go unsafe 包

go unsafe 包

作者头像
solate
发布于 2022-05-09 05:28:56
发布于 2022-05-09 05:28:56
57300
代码可运行
举报
文章被收录于专栏:solate 杂货铺solate 杂货铺
运行总次数:0
代码可运行

go unsafe 包

unsafe包是不安全的,可以绕过go内存安全机制,直接对内存进行读写。

指针转换

go 语言是强类型的,所以一般情况不允许不同类型指针进行转换

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	i:= 10
	ip:=&i
	var fp *float64 = (*float64)(ip)
	fmt.Println(fp)
}

// cannot convert ip (type *int) to type *float64

如果需要转换的时候,需要用的unsafe.Pointer

unsafe.Pointer

unsafe.Pointer 是一种特殊意义的指针,可以表示任意类型的地址

我们使用unsafe.Pointer,就可以将int指针改为float64的指针并进行运算,下面是3倍乘法运算。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	i:= 10
	ip:=&i
	var fp *float64 = (*float64)(unsafe.Pointer(ip))
	*fp = *fp * 3
	fmt.Println(i) // 30
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package. It represents the type of an arbitrary Go expression.
type ArbitraryType int
type Pointer *ArbitraryType

ArbitraryType 可以表示任何类型, 而 unsafe.Pointer 又是 *ArbitraryType,也就是说 unsafe.Pointer 是任何类型的指针,也就是一个通用型的指针。

unsafe.Pointer可以表示指针了,但是 unsafe.Pointer 不能进行运算,比如不支持 +(加号)运算符操作,

这个时候就需要用到 uintptr

uintptr

在 builtin/builtin.go 包中,是一种类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptr

通过uintptr,可以对指针偏移进行计算, 这样就可以像c语言一样访问内存,对内存进行读写,真正操作内存。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	type person struct {
		name string
		age int
	}

	p := new(person)
	pName := (*string)(unsafe.Pointer(p)) // 偏移量为0
	*pName = "test"
	pAge := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(p))+unsafe.Offsetof(p.age))) // 指针偏移
	*pAge = 20
	fmt.Println(p) //&{test 20}
}

对一个结构体进行内存操作赋值。

age 字段不是 person 的第一个字段,要修改它必须要进行指针偏移运算。所以需要先把指针变量 p 通过 unsafe.Pointer 转换为 uintptr, 这样才能进行地址运算.这个偏移量可以通过函数 unsafe.Offsetof 计算出来,该函数返回的是一个 uintptr 类型的偏移量, 有了这个偏移量就可以通过 + 号运算符获得正确的 age 字段的内存地址了,也就是通过 unsafe.Pointer 转换后的 *int 类型的指针变量 pAge。

注意:

如果要进行指针运算,要先通过 unsafe.Pointer 转换为 uintptr 类型的指针。 指针运算完毕后,还要通过 unsafe.Pointer 转换为真实的指针类型(比如示例中的 *int 类型), 这样可以对这块内存进行赋值或取值操作。

指针运算的核心在于它操作的是一个个内存地址,通过内存地址的增减,就可以指向一块块不同的内存并对其进行操作,而且不必知道这块内存被起了什么名字(变量名)

指针转换规则

Go 语言中存在三种类型的指针: 常用的 *T、unsafe.Pointer 及 uintptr。

  1. 任何类型的 *T 都可以转换为 unsafe.Pointer;
  2. unsafe.Pointer 也可以转换为任何类型的 *T;
  3. unsafe.Pointer 可以转换为 uintptr;
  4. uintptr 也可以转换为 unsafe.Pointer。

unsafe.Sizeof

Sizeof 函数可以返回一个类型所占用的内存大小,这个大小只与类型有关, 和类型对应的变量存储的内容大小无关,比如 bool 型占用一个字节、int8 也占用一个字节。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fmt.Println(unsafe.Sizeof(true))
fmt.Println(unsafe.Sizeof(int8(0)))
fmt.Println(unsafe.Sizeof(int16(10)))
fmt.Println(unsafe.Sizeof(int32(10000000)))
fmt.Println(unsafe.Sizeof(int64(10000000000000)))
fmt.Println(unsafe.Sizeof(int(10000000000000000)))

对于和平台有关的 int 类型,要看平台是 32 位还是 64 位,会取最大的

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go通关17:Go指针和unsafe.Pointer有什么区别?
在 Go 语言中,处于安全考虑,是不允许两个指针类型进行转换的,比如 *int 不能转为 *float64。
微客鸟窝
2021/08/18
3270
Go看源码必会知识之unsafe包
众所周知,Go语言被设计成一门强类型的静态语言,那么他的类型就不能改变了,静态也是意味着类型检查在运行前就做了。所以在Go语言中是不允许两个指针类型进行转换的,使用过C语言的朋友应该知道这在C语言中是可以实现的,Go中不允许这么使用是处于安全考虑,毕竟强制转型会引起各种各样的麻烦,有时这些麻烦很容易被察觉,有时他们却又隐藏极深,难以察觉。大多数读者可能不明白为什么类型转换是不安全的,这里用C语言举一个简单的例子:
Golang梦工厂
2022/07/08
2830
Go看源码必会知识之unsafe包
Go里面的unsafe包详解
原文:http://www.tapirgames.com/blog/golang-unsafe
我的小碗汤
2018/08/22
1.2K0
Go语言实战笔记(二十七)| Go unsafe Pointer
Go语言在设计的时候,为了编写方便、效率高以及降低复杂度,被设计成为一门强类型的静态语言。强类型意味着一旦定义了,它的类型就不能改变了;静态意味着类型检查在运行前就做了。
飞雪无情
2018/08/28
4570
你不知道的Go unsafe.Pointer uintptr原理和玩法
这个类型比较重要,它是实现定位和读写的内存的基础,Go runtime大量使用它。官方文档对该类型有四个重要描述:
sunsky
2020/08/20
1.8K0
你不知道的Go unsafe.Pointer uintptr原理和玩法
深度解密Go语言之unsafe
个人认为,学习本身并不是一件轻松愉快的事情,寓教于乐是个美好的愿望。想要深刻地领悟,就得付出别人看不见的努力。学习从来都不会是一件轻松的事情,枯燥是正常的。耐住性子,深入研究某个问题,读书、看文章、写博客都可以,浮躁时代做个专注的人!
梦醒人间
2019/06/03
6800
Go 指针、uintptr、unsafe.Pointer之间如何转换
uintptr是一个无符号的整型,它可以保存一个指针地址,它可以进行指针运算。想取值需要转成unsafe.Pointer后, 需再转到相对应的指针类型。
小许code
2023/02/07
1.7K0
Go 指针、uintptr、unsafe.Pointer之间如何转换
Go 与 C 的指针
C 和 Go 都是有指针概念的语言,这篇文章主要借这两者之间的异同来加深对 Go 指针的理解和使用。
gopher云原生
2021/10/18
7770
Go指针的使用限制和突破之路
大家好呀,今天网管想在这篇文章里好好跟大家聊一下 Go 语言指针这个话题,相较于 C 而言,Go 语言在设计时为了使用安全给指针在类型和运算上增加了限制,这让Go程序员既可以享受指针带来的便利,又避免了指针的危险性。除了常规的指针外,Go 语言在 unsafe 包里其实还通过 unsafe.Pointer 提供了通用指针,通过这个通用指针以及 unsafe 包的其他几个功能又让使用者能够绕过 Go 语言的类型系统直接操作内存进行例如:指针类型转换,读写结构体私有成员这样操作。网管觉得正是因为功能强大同时伴随着操作不慎读写了错误的内存地址即会造成的严重后果所以 Go 语言的设计者才会把这些功能放在 unsafe 包里。其实也没有想得那么不安全,掌握好了使用得当还是能带来很大的便利的,在一些偏向底层的源码中 unsafe 包使用的频率还是不低的。对于励志成为高阶 Gopher 的各位,这也是一项必不可少需要掌握的技能啦。接下来网管就带大家从基本的指针使用方法和限制开始看看怎么用 unsafe 包跨过这些限制直接读写内存。
KevinYan
2021/01/13
1K0
Go的内存对齐和指针运算详解和实践
位模式:内存由字节组成.每个字节由8位bit组成,每个bit状态只能是0或1.所谓位模式,就是变量所占用内存的所有bit的状态的序列指针大小:一个指针的大小是多少呢?在32位操作系统上,指针大小是4个字节,在64位操作系统上,指针的大小是8字节,所以uintptr能够容纳任何指针的位模式,总的说uintptr表示的指针地址的值,可以用来进行数值计算GC不会把uintptr当作指针,uintptr不会持有一个对象,uintptr类型的目标会被GC回收
阿伟
2020/02/12
1.4K0
Go的内存对齐和指针运算详解和实践
unsafe.Pointer与uintptr
上面的例子中,将 uintptr 值存储在变量 ptr 中,实际上这是一个错误的用法
leobhao
2024/11/29
660
Golang 语言中的非类型安全指针
Golang 语言中的 unsafe 包中包含的操作会绕过 Golang 程序的类型安全检查,直接操作内存,从而达到提升性能的目的。导入 unsafe 包可能是不可移植(non-portable)的(随着 Golang 的版本迭代,可能会失效),并且不受 Go 1 兼容性准则的保护,所以我们应该谨慎使用。
frank.
2021/04/16
9120
Go 中普通指针、unsafe.Pointer 与 uintptr 之间的关系和指针运算
指针运算就是对指针类型的变量做常规数学运算,例如加减操作,实现地址的偏移。指针运算在 C 语言中是原生支持的,可以直接在指针变量上做加减,例如:
菜皮日记
2023/12/18
2980
Go:unsafe包使用技巧与风险防范
Go语言中的unsafe包是一个充满争议的特性,它提供了一种突破Go语言类型安全的方式,允许程序员执行任意的指针算法并且直接读写内存。这种能力虽然强大,但使用不当极易导致程序错误,甚至崩溃。因此,unsafe包应当谨慎使用,通常只在涉及底层系统交互或者对性能要求极高的场景中才会用到。
运维开发王义杰
2024/04/30
2680
Go:unsafe包使用技巧与风险防范
golang unsafe.Pointer与uintptr
理论上说指针不过是一个数值,即一个uint,但实际上在go中unsafe.Pointer是不能通过强制类型转换为一个uint的,只能将unsafe.Pointer强制类型转换为一个uintptr。
Orlion
2024/09/02
1080
Go语言实战笔记(二十六)| Go unsafe 包之内存布局
unsafe,顾名思义,是不安全的,Go定义这个包名也是这个意思,让我们尽可能的不要使用它,如果你使用它,看到了这个名字,也会想到尽可能的不要使用它,或者更小心的使用它。
飞雪无情
2018/08/28
4340
Go unsafe包底层编程细节详解 【Go语言圣经笔记】
Go语言的设计包含了诸多安全策略,限制了可能导致程序运行出错的用法。编译时类型检查可以发现大多数类型不匹配的操作,例如两个字符串做减法的错误。字符串、map、slice和chan等所有的内置类型,都有严格的类型转换规则。
Steve Wang
2021/12/06
1.3K0
Go unsafe包底层编程细节详解 【Go语言圣经笔记】
Go语言学习10-指针类型
书接上篇,Huazie 带大家了解了Go语言的《结构体类型》,本篇将要介绍Go语言的指针类型。
huazie
2024/10/07
1240
Go语言学习10-指针类型
详解Go变量类型的内存布局
每当我们编写任何程序时,我们都需要在内存中存储一些数据/信息。数据存储在特定地址的存储器中。内存地址看起来像0xAFFFF(这是内存地址的十六进制表示)。
sunsky
2020/08/20
1.9K0
详解Go变量类型的内存布局
Go 数据类型篇(八):指针使用入门与 unsafe.Pointer
我们已经知道,变量的本质对一块内存空间的命名,我们可以通过引用变量名来使用这块内存空间存储的值,而指针则是用来指向这些变量值所在内存地址的值。
学院君
2023/03/03
8590
Go 数据类型篇(八):指针使用入门与 unsafe.Pointer
相关推荐
Go通关17:Go指针和unsafe.Pointer有什么区别?
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验