# Go 语言中的 uintptr 和 unsafe.Pointer 区别
# 1. unsafe.Pointer
unsafe.Pointer 是 Go 语言中的特殊指针类型,它可以:
- 绕过 Go 的类型系统,实现任意类型指针间的转换
- 用于指向任意类型的指针转换模式:
*T1 -> unsafe.Pointer -> *T2 |
- 保持指针语义,会被 GC 追踪
- 不能直接进行指针算术运算
# 主要特点:
- 可以存储任何类型的地址
- 可以和普通指针互相转换
- 保持对目标对象的引用关系
- 参与 GC 扫描
# 2. uintptr
uintptr 是一个整数类型,它的大小足够存储一个指针的值。主要特点:
- 本质是一个无符号整数,而不是指针
- 可以进行算术运算
- 不会被 GC 追踪
- 不保证其值指向的内存对象依然有效
# 使用场景:
- 指针偏移量计算
- 进行地址相关的位运算
- 存储地址的数值表示
# 3. 关键区别对比
| 特性 | unsafe.Pointer | uintptr |
|---|---|---|
| 类型本质 | 指针类型 | 整数类型 |
| GC 追踪 | 是 | 否 |
| 算术运算 | 不支持 | 支持 |
| 类型转换 | 可与任意指针类型互转 | 仅与整数类型互转 |
| 内存安全 | 相对安全 | 不安全 |
# 4. 使用示例
func example() { | |
// 创建一个示例结构体 | |
type MyStruct struct { | |
a int | |
b string | |
} | |
x := &MyStruct{a: 1, b: "hello"} | |
//unsafe.Pointer 使用 | |
pointer := unsafe.Pointer(x) | |
//uintptr 使用 | |
address := uintptr(pointer) | |
// 警告:以下操作可能不安全 | |
offsetAddress := address + unsafe.Sizeof(int(0)) // 指向 b 字段 | |
// 转回 unsafe.Pointer 必须一气呵成 | |
bPointer := unsafe.Pointer(offsetAddress) | |
bString := (*string)(bPointer) | |
fmt.Println(*bString) // "hello" | |
} |
# 5. 使用注意事项
- 尽量避免使用 unsafe 包,除非确实需要
- uintptr 转换后立即使用,不要存储
- 指针计算必须遵循内存对齐规则
- GC 可能会在 uintptr 计算过程中移动对象
警告:不恰当使用 unsafe 包可能导致未定义行为,应当谨慎使用。