精华内容
下载资源
问答
  • Go unsafe 包的使用详解

    2020-09-18 02:02:41
    主要介绍了Go unsafe 包的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • cgo: C的struct转换为go unsafe.Pointer的办法 如果go build时报错: cannot use _cgo5 (type _Ctype_struct__xx) as type unsafe.Pointer in argument. 例如C函数中函数声明是int SetUserData(void * userData), ...

    cgo: C的struct转换为go unsafe.Pointer的办法

    如果go build时报错:
    cannot use _cgo5 (type _Ctype_struct__xx) as type unsafe.Pointer in argument.
    例如C函数中函数声明是int SetUserData(void * userData), 其中userData为一个struct,
    可用这个办法将C的struct转换为go unsafe.Pointer:

    var a C.UserData
    udata := unsafe.Pointer(&a)
    C.SetUserData(udata)
    
    展开全文
  • go unsafe包使用

    2019-08-22 17:17:46
    Go 还有非类型安全的指针,这就是 unsafe 包提供的 unsafe.Pointer。在某些情况下,它会使代码更高效,当然,也更危险。 unsafe 包用于 Go 编译器,在编译阶段使用。从名字就可以看出来,它是不安全的,官方并不建议...

    转载自stefno的博客

    什么是 unsafe
    前面所说的指针是类型安全的,但它有很多限制。Go 还有非类型安全的指针,这就是 unsafe 包提供的 unsafe.Pointer。在某些情况下,它会使代码更高效,当然,也更危险。

    unsafe 包用于 Go 编译器,在编译阶段使用。从名字就可以看出来,它是不安全的,官方并不建议使用。我在用 unsafe 包的时候会有一种不舒服的感觉,可能这也是语言设计者的意图吧。

    但是高阶的 Gopher,怎么能不会使用 unsafe 包呢?它可以绕过 Go 语言的类型系统,直接操作内存。例如,一般我们不能操作一个结构体的未导出成员,但是通过 unsafe 包就能做到。unsafe 包让我可以直接读写内存,还管你什么导出还是未导出。


    为什么有 unsafe
    Go 语言类型系统是为了安全和效率设计的,有时,安全会导致效率低下。有了 unsafe 包,高阶的程序员就可以利用它绕过类型系统的低效。因此,它就有了存在的意义,阅读 Go 源码,会发现有大量使用 unsafe 包的例子。


    unsafe 实现原理
    我们来看源码:

    type ArbitraryType int
    type Pointer *ArbitraryType
    

    从命名来看,Arbitrary 是任意的意思,也就是说 Pointer 可以指向任意类型,实际上它类似于 C 语言里的 void*。

    unsafe 包还有其他三个函数:

    func Sizeof(x ArbitraryType) uintptr
    func Offsetof(x ArbitraryType) uintptr
    func Alignof(x ArbitraryType) uintptr
    
    • Sizeof 返回类型 x 所占据的字节数,但不包含 x 所指向的内容的大小。例如,对于一个指针,函数返回的大小为 8 字节(64位机上),一个 slice 的大小则为 slice header 的大小。
    • Offsetof 返回结构体成员在内存中的位置离结构体起始处的字节数,所传参数必须是结构体的成员。
    • Alignof 返回 m,m 是指当类型进行内存对齐时,它分配到的内存地址能整除 m。

    注意到以上三个函数返回的结果都是 uintptr 类型,这和 unsafe.Pointer 可以相互转换。三个函数都是在编译期间执行,它们的结果可以直接赋给 const 型变量。另外,因为三个函数执行的结果和操作系统、编译器相关,所以是不可移植的。

    综上所述,unsafe 包提供了 2 点重要的能力:

    任何类型的指针和 unsafe.Pointer 可以相互转换。
    uintptr 类型和 unsafe.Pointer 可以相互转换。
    在这里插入图片描述

    还有一点要注意的是,uintptr 并没有指针的语义,意思就是 uintptr 所指向的对象会被 gc 无情地回收。而 unsafe.Pointer 有指针语义,可以保护它所指向的对象在“有用”的时候不会被垃圾回收。


    unsafe使用实例

    package main
    
    import (
    	"fmt"
    	"let_me_go/network"
    	"reflect"
    	"unsafe"
    )
    
    // 测试unsafe包
    func main() {
    	ip := new(network.IP)
    	ip.SetHost("127.0.0.1")
    	ip.SetPort(8080)
    
    	fmt.Println(*ip)
    
    	// 测试unsafe 访问/修改 结构体私有属性
    	i := (*string)(unsafe.Pointer(ip))
    	fmt.Println(*i)
    	*i = "192.168.1.1"
    	fmt.Println(*ip)
    
    	// 进行指针偏移
    	// 使用unsafe.Sizeof计算结构体每个成员变量所占的地址位
    	t := (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(ip)) + unsafe.Sizeof(ip.GetHost())))
    	fmt.Println(*t)
    	*t = 80
    	fmt.Println(*ip)
    
    	// 使用unsafe 进行string和slice的相互转换
    	s := "hello world"
    	bytes := string2Bytes(s)
    	for _, value := range bytes {
    		fmt.Println(value)
    	}
    
    	fmt.Println(bytes2String(bytes))
    }
    
    func string2Bytes(s string) []byte {
    	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
    
    	sliceHeader := reflect.SliceHeader{
    		Data: stringHeader.Data,
    		Len:  stringHeader.Len,
    		Cap:  stringHeader.Len,
    	}
    
    	return *(*[]byte)(unsafe.Pointer(&sliceHeader))
    }
    
    func bytes2String(bytes []byte) string {
    	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
    
    	stringHeader := reflect.StringHeader{
    		Data: sliceHeader.Data,
    		Len:  sliceHeader.Len,
    	}
    
    	return *(*string)(unsafe.Pointer(&stringHeader))
    }
    

    运行结果

    {127.0.0.1 8080}
    127.0.0.1
    {192.168.1.1 8080}
    8080
    {192.168.1.1 80}
    104
    101
    108
    108
    111
    32
    119
    111
    114
    108
    100
    hello world
    
    展开全文
  • go unsafe的用处

    2018-09-21 19:29:27
    解释不为安排指针:  unsafe.Pointer其实就是类似C的void *,在golang中是用于各种... 正常的情况来说go语言的中的结构私有变量不能直接被访问或者直接被修改,但是可以通过unsafe的操作来直接对么有变量进入取值...

    解释不为安排指针:

      unsafe.Pointer其实就是类似C的void *,在golang中是用于各种指针相互转换的桥梁。uintptr是golang的内置类型,是能存储指针的整型,uintptr的底层类型是int,它和unsafe.Pointer可相互转换。

      正常的情况来说go语言的中的结构私有变量不能直接被访问或者直接被修改,但是可以通过unsafe的操作来直接对么有变量进入取值或者修改

    package main
    
    import (
    	_ "ORMTest/routers"
    	"fmt"
    	"unsafe"
    )
    
    func main() {
    	d := struct {
    		s string
    		i int
    	}{"abc", 100}
    	p := uintptr(unsafe.Pointer(&d)) // *struct -> Pointer -> uintptr
    	p += unsafe.Offsetof(d.s)        // uintptr + offset
    
    	p2 := unsafe.Pointer(p) // uintptr -> Pointer
    	px := (*int)(p2)        // Pointer -> *int
    	*px = 200               // d.s = 200
    	fmt.Printf("%#v\n", d)
    }
    

    输出

     

    展开全文
  • 在上一篇文章 《深入理解 Go Slice》 中,大家会发现其底层数据结构使用了 unsafe.Pointer。因此想着再介绍一下其关联知识 原文地址:有点不安全却又一亮的 Go unsafe.Pointer 前言 在大家学习 Go 的时候,肯定都学...
        

    在上一篇文章 《深入理解 Go Slice》 中,大家会发现其底层数据结构使用了 unsafe.Pointer。因此想着再介绍一下其关联知识

    原文地址:有点不安全却又一亮的 Go unsafe.Pointer

    前言

    在大家学习 Go 的时候,肯定都学过 “Go 的指针是不支持指针运算和转换” 这个知识点。为什么呢?

    首先,Go 是一门静态语言,所有的变量都必须为标量类型。不同的类型不能够进行赋值、计算等跨类型的操作。那么指针也对应着相对的类型,也在 Compile 的静态类型检查的范围内。同时静态语言,也称为强类型。也就是一旦定义了,就不能再改变它

    错误示例

    func main(){
        num := 5
        numPointer := &num
    
        flnum := (*float32)(numPointer)
        fmt.Println(flnum)
    }

    输出结果:

    # command-line-arguments
    ...: cannot convert numPointer (type *int) to type *float32

    在示例中,我们创建了一个 num 变量,值为 5,类型为 int。取了其对于的指针地址后,试图强制转换为 *float32,结果失败...

    unsafe

    针对刚刚的 “错误示例”,我们可以采用今天的男主角 unsafe 标准库来解决。它是一个神奇的包,在官方的诠释中,有如下概述:

    • 围绕 Go 程序内存安全及类型的操作
    • 很可能会是不可移植的
    • 不受 Go 1 兼容性指南的保护

    简单来讲就是,不怎么推荐你使用。因为它是 unsafe(不安全的),但是在特殊的场景下,使用了它。可以打破 Go 的类型和内存安全机制,让你获得眼前一亮的惊喜效果 ?

    Pointer

    为了解决这个问题,需要用到 unsafe.Pointer。它表示任意类型且可寻址的指针值,可以在不同的指针类型之间进行转换(类似 C 语言的 void * 的用途)

    其包含四种核心操作:

    • 任何类型的指针值都可以转换为 Pointer
    • Pointer 可以转换为任何类型的指针值
    • uintptr 可以转换为 Pointer
    • Pointer 可以转换为 uintptr

    在这一部分,重点看第一点、第二点。你再想想怎么修改 “错误示例” 让它运行起来?

    func main(){
        num := 5
        numPointer := &num
    
        flnum := (*float32)(unsafe.Pointer(numPointer))
        fmt.Println(flnum)
    }

    输出结果:

    0xc4200140b0

    在上述代码中,我们小加改动。通过 unsafe.Pointer 的特性对该指针变量进行了修改,就可以完成任意类型(*T)的指针转换

    需要注意的是,这时还无法对变量进行操作或访问。因为不知道该指针地址指向的东西具体是什么类型。不知道是什么类型,又如何进行解析呢。无法解析也就自然无法对其变更了

    Offsetof

    在上小节中,我们对普通的指针变量进行了修改。那么它是否能做更复杂一点的事呢?

    type Num struct{
        i string
        j int64
    }
    
    func main(){
        n := Num{i: "EDDYCJY", j: 1}
        nPointer := unsafe.Pointer(&n)
    
        niPointer := (*string)(unsafe.Pointer(nPointer))
        *niPointer = "煎鱼"
    
        njPointer := (*int64)(unsafe.Pointer(uintptr(nPointer) + unsafe.Offsetof(n.j)))
        *njPointer = 2
    
        fmt.Printf("n.i: %s, n.j: %d", n.i, n.j)
    }
    

    输出结果:

    n.i: 煎鱼, n.j: 2

    在剖析这段代码做了什么事之前,我们需要了解结构体的一些基本概念:

    • 结构体的成员变量在内存存储上是一段连续的内存
    • 结构体的初始地址就是第一个成员变量的内存地址
    • 基于结构体的成员地址去计算偏移量。就能够得出其他成员变量的内存地址

    再回来看看上述代码,得出执行流程:

    • 修改 n.i 值:i 为第一个成员变量。因此不需要进行偏移量计算,直接取出指针后转换为 Pointer,再强制转换为字符串类型的指针值即可
    • 修改 n.j 值:j 为第二个成员变量。需要进行偏移量计算,才可以对其内存地址进行修改。在进行了偏移运算后,当前地址已经指向第二个成员变量。接着重复转换赋值即可

    需要注意的是,这里使用了如下方法(来完成偏移计算的目标):

    1、uintptr:uintptr 是 Go 的内置类型。返回无符号整数,可存储一个完整的地址。后续常用于指针运算

    type uintptr uintptr

    2、unsafe.Offsetof:返回成员变量 x 在结构体当中的偏移量。更具体的讲,就是返回结构体初始位置到 x 之间的字节数。需要注意的是入参 ArbitraryType 表示任意类型,并非定义的 int。它实际作用是一个占位符

    func Offsetof(x ArbitraryType) uintptr

    在这一部分,其实就是巧用了 Pointer 的第三、第四点特性。这时候就已经可以对变量进行操作了 ?

    错误示例

    func main(){
        n := Num{i: "EDDYCJY", j: 1}
        nPointer := unsafe.Pointer(&n)
        ...
    
        ptr := uintptr(nPointer)
        njPointer := (*int64)(unsafe.Pointer(ptr + unsafe.Offsetof(n.j)))
        ...
    }

    这里存在一个问题,uintptr 类型是不能存储在临时变量中的。因为从 GC 的角度来看,uintptr 类型的临时变量只是一个无符号整数,并不知道它是一个指针地址

    因此当满足一定条件后,ptr 这个临时变量是可能被垃圾回收掉的,那么接下来的内存操作,岂不成迷?

    总结

    简洁回顾两个知识点。第一是 unsafe.Pointer 可以让你的变量在不同的指针类型转来转去,也就是表示为任意可寻址的指针类型。第二是 uintptr 常用于与 unsafe.Pointer 打配合,用于做指针运算,巧妙地很

    最后还是那句,没有特殊必要的话。是不建议使用 unsafe 标准库,它并不安全。虽然它常常能让你眼前一亮 ?

    展开全文
  • Go unsafe Pointer

    2018-08-03 15:48:00
    2019独角兽企业重金招聘...还有,整个unsafe包都是用于Go编译器的,不用运行时,在我们编译的时候,Go编译器已经把他们都处理了。 转载于:https://my.oschina.net/fileoptions/blog/1922151
  • go unsafe包使用详解

    2020-03-13 00:21:31
    例如,当使用系统调用和Go结构必须具有与C结构相同的内存布局时,您可能别无选择,只能使用unsafe。关于指针操作,在unsafe包官方定义里有四个描述: 任何类型的指针都可以被转化为Pointer Pointer可以被转化为任何...
  • Go unsafe

    2017-02-17 18:01:00
    Go unsafeunsafe包概述 直到现在(Go1.7),unsafe包含以下资源: 三个函数: // unsafe.Sizeof函数返回操作数在内存中的字节大小,参数可以是任意类型的表达式,但是它并不会对表达式进行求值. // ...
  • go unsafe package 的学习

    2017-07-25 17:16:11
    go 不像c 那样直接可以对指针做一些操作,所以go ...2. unsafe.Pointer:通用指针类型,用于转换不同类型的指针,不能进行指针运算。 3. uintptr:用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintp
  • https://my.oschina.net/goal/blog/193698 https://my.oschina.net/xinxingegeya/blog/729673 ... unsafe.Pointer 是实现定位预读写的内存基础。 (1)任何类型的指针都可以被转化为Pointer (2)Pointer...
  • unsafe.Pointer 这个类型比较重要,它是实现定位和读写的内存的基础,Go runtime大量使用它。官方文档对该类型有四个重要描述: (1)任何类型的指针都可以被转化为Pointer (2)Pointer可以被转化为任何类型的指针...
  • unsafe,顾名思义,是不安全的,Go定义这个包名也是这个意思,让我们尽可能的不要使用它,如果你使用它,看到了这个名字,也会想到尽可能的不要使用它,或者更小心的使用它。 虽然这个包不安全,但是它也有它的优势...
  • Go语言实战》读书笔记,未完待续,欢迎扫码关注公众号flysnow_org或者网站http://www.flysnow.org/,第一时间看后续笔记。觉得有帮助的话,顺手分享到朋友圈吧...
  • Go语言实战》读书笔记,未完待续,欢迎扫码关注公众号flysnow_org或者网站http://www.flysnow.org/,第一时间看后续笔记。觉得有帮助的话,顺手分享到朋友圈吧...
  • 假如我们有这样一个包:iface.go package iface func GetAddFunc() interface{} { return add } type i32 int32 func add(a, b i32) i32 { return a + b } 希望可以在包外执行add函数,怎么办?此处,因为...
  • Gounsafe

    2017-12-22 10:46:56
    Go官方包提供了一个unsafe包,在这个包里面有含够绕开Go程序类型安全的操作。 既然是unsafe包,使用起来一定要特别小心。尽管unsafe有点危险,但是它也难以置信的有用。unsafe的操作: A pointer value of any type ...
  • 深入理解Go——unsafe

    2020-10-26 10:48:33
    文章目录Go指针和unsafe.Pointerslice与unsafe.Pointer总结unsafe.Pointer Go指针和unsafe.Pointer Go 语言的指针相比 C 的指针有很多限制,是为了享受指针带来的便利,又避免了指针的危险性。 比如 Go的指针不能...
  • Go-unsafe详解

    千次阅读 2015-08-11 17:24:01
    package unsafe // 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 Arbitrary
  • 图解Gounsafe.Pointer\相信看过Go源码的同学已经对unsafe.Pointer非常的眼熟,因为这个类型可以说在源码中是随处可见:map、channel、interface、slice...但凡你能想到的内容,基本都会有unsafe.Pointer的影子。看...
  • 图解Gounsafe.Pointer

    2020-04-02 00:32:24
    相信看过Go源码的同学已经对unsafe.Pointer非常的眼熟,因为这个类型可以说在源码中是随处可见:map、channel、interface、slice…但凡你能想到的内容,基本都会有unsafe.Pointer的影子。 看字面意思,unsafe....
  • [go] unsafe

    2016-04-25 12:48:11
    uintptr是go的内置类型,用于指针运算,其底层基于int类型。uintptr不是指针,GC会回收uintptr类型的对象。unsafe.Sizeof函数返回的就是uintptr类型的值,表达式的大小:var p float64 = 99 fmt.Println(reflect....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,869
精华内容 747
关键字:

gounsafe