首页 > 后端开发 > Golang > 正文

如何存储指针指向的地址?

DDD
发布: 2025-08-01 18:24:16
原创
573人浏览过

如何存储指针指向的地址?

本文旨在讲解如何在 Go 语言中存储 new() 函数返回的指针所指向的内存地址。虽然可以使用 unsafe 包中的 Pointer 类型,但存在潜在的安全风险。本文将探讨更安全且更实用的方法,并简要介绍 reflect 和 unsafe 包的相关用法,帮助开发者更好地理解和使用指针地址。

在 Go 语言中,如果你需要存储 new() 函数分配的内存地址,并将其用作 map 的键,直接使用指针类型可能会遇到问题,因为 Go 是一种类型安全的语言。以下是一些建议和方法,帮助你安全有效地存储和使用指针地址。

使用 unsafe.Pointer (不推荐)

unsafe 包提供了一种将任何类型的指针转换为 unsafe.Pointer 的方法。unsafe.Pointer 可以转换为 uintptr,后者可以作为 map 的键。但是,使用 unsafe 包具有潜在的风险,因为它绕过了 Go 的类型安全检查。

package main

import (
    "fmt"
    "time"
    "unsafe"
)

type T struct {
    a, b int
}

func main() {
    var t int64 = time.Now().UnixNano()
    memmap := make(map[uintptr]int64)
    fmt.Printf("%d\n", t)

    var ptr *T = new(T)
    ptr.a = 1
    ptr.b = 2
    fmt.Printf("%d %d %p %T\n", ptr.a, ptr.b, ptr, ptr)

    // 将指针转换为 unsafe.Pointer,再转换为 uintptr
    addr := uintptr(unsafe.Pointer(ptr))
    memmap[addr] = t

    fmt.Printf("Address stored in map: %x\n", addr)

    // 从map中取出数据,需要将uintptr转换回指针才能访问原始数据,非常危险!
    // 强烈不建议这样做
    // restoredPtr := (*T)(unsafe.Pointer(addr))
    // fmt.Printf("Restored value: %d %d\n", restoredPtr.a, restoredPtr.b)
}
登录后复制

注意事项:

  • 使用 unsafe.Pointer 需要谨慎,因为它可能导致程序崩溃或产生未定义的行为。
  • 在垃圾回收过程中,如果指针不再被引用,内存可能会被释放,导致 unsafe.Pointer 指向无效的内存地址。
  • 不建议从 uintptr 转换回原始指针类型,除非你非常确定内存仍然有效。

使用类型和地址的元组

更安全和推荐的方法是使用类型和地址的元组作为 map 的键。这可以确保类型安全,并避免 unsafe 包的潜在风险。虽然这种方法增加了复杂性,但它提供了更好的控制和安全性。

存了个图
存了个图

视频图片解析/字幕/剪辑,视频高清保存/图片源图提取

存了个图 17
查看详情 存了个图
package main

import (
    "fmt"
    "reflect"
    "time"
)

type T struct {
    a, b int
}

type AddressKey struct {
    Type reflect.Type
    Addr uintptr
}

func main() {
    var t int64 = time.Now().UnixNano()
    memmap := make(map[AddressKey]int64)
    fmt.Printf("%d\n", t)

    var ptr *T = new(T)
    ptr.a = 1
    ptr.b = 2
    fmt.Printf("%d %d %p %T\n", ptr.a, ptr.b, ptr, ptr)

    // 使用 reflect 获取类型信息和地址
    key := AddressKey{
        Type: reflect.TypeOf(ptr).Elem(), // 获取指针指向的类型
        Addr: reflect.ValueOf(ptr).Pointer(), // 获取指针地址
    }

    memmap[key] = t

    fmt.Printf("Address stored in map: %v\n", key)

    // 从map中取出数据
    value, ok := memmap[key]
    if ok {
        fmt.Printf("Value from map: %d\n", value)
    }
}
登录后复制

代码解释:

  1. AddressKey 结构体: 定义了一个结构体,用于存储类型信息 (reflect.Type) 和地址 (uintptr)。
  2. reflect.TypeOf(ptr).Elem(): 获取指针 ptr 指向的类型,例如 T。
  3. reflect.ValueOf(ptr).Pointer(): 获取指针 ptr 的地址,返回 uintptr 类型。
  4. memmap[key] = t: 将 AddressKey 结构体作为键,将时间戳 t 作为值,存储到 map 中。

优点:

  • 类型安全:使用 reflect 包获取类型信息,避免了直接使用 unsafe.Pointer 带来的类型安全问题。
  • 明确性:明确地存储了类型信息和地址信息,方便后续使用。

缺点:

  • 复杂性:相比直接使用 unsafe.Pointer,代码更加复杂。
  • 性能:使用 reflect 包可能会带来一定的性能损耗。

总结

在 Go 语言中存储指针地址需要谨慎。虽然可以使用 unsafe.Pointer,但存在安全风险。更安全的方法是使用类型和地址的元组,这需要使用 reflect 包获取类型信息和地址信息。选择哪种方法取决于你的具体需求和对安全性的考虑。建议优先选择类型安全的方案,避免使用 unsafe 包,除非你有充分的理由并且了解潜在的风险。

以上就是如何存储指针指向的地址?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号