您的位置 首页 golang

golang2021数据格式(94)unsafe修改私有成员

对于一个结构体,通过 offset 函数可以获取结构体成员的偏移量,进而获取成员的地址,读写该地址的内存,就可以达到改变成员值的目的。

这里有一个内存分配相关的事实: 结构体 会被分配一块连续的内存,结构体的地址也代表了第一个成员的地址。

我们来看一个例子:

 1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

package main

import (
            “fmt”
            “unsafe”
    )

type   Programmer struct {
            name string
            language string
    }

func   main() {
            p := Programmer{“stefno”, “go”}
            fmt.Println(p)
           
            name := (*string)(unsafe.Pointer(&p))
            *name = “qcrao”

lang := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&p))   + unsafe.Offsetof(p.language)))
            *lang = “Golang”

fmt.Println(p)
    }

运行代码,输出:

1
    2

{stefno go}
    {qcrao Golang}

name 是结构体的第一个成员,因此可以直接将 &p 解析成 *string。这一点,在前面获取 map 的 count 成员时,用的是同样的原理。

对于结构体的私有成员,现在有办法可以通过 unsafe.Pointer 改变它的值了。

我把 Programmer 结构体升级,多加一个字段:

1
    2
    3
    4
    5

type   Programmer struct {
            name string
            age int
            language string
    }

并且放在其他包,这样在 main 函数中,它的三个字段都是私有成员变量,不能直接修改。但我通过 unsafe.Sizeof() 函数可以获取成员大小,进而计算出成员的地址,直接修改内存。

1
    2
    3
    4
    5
    6
    7
    8
    9

func   main() {
            p := Programmer{“stefno”, 18, “go”}
            fmt.Println(p)

lang := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&p))   + unsafe.Sizeof(int(0)) + unsafe.Sizeof(string(“”))))
            *lang = “Golang”

fmt.Println(p)
    }

输出:

1
    2

{stefno 18 go}
    {stefno 18 Golang}

文章来源:智云一二三科技

文章标题:golang2021数据格式(94)unsafe修改私有成员

文章地址:https://www.zhihuclub.com/99274.shtml

关于作者: 智云科技

热门文章

网站地图