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修改私有成员


展开阅读全文

页面更新:2024-05-01

标签:成员   目的   这一点   字段   变量   函数   例子   分配   事实   原理   大小   内存   结构   办法   地址   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top