Go中 uintptr和 unsafe.Pointer 的区别?
时间: 2024-09-27 11:02:28 浏览: 27
在Go语言中,`uintptr` 和 `unsafe.Pointer` 都用于操作底层内存,但它们之间有着本质的区别:
1. `uintptr`:这是一个无类型的整型常量,它表示的是一个内存地址的大小,通常是一个系统特定的宽度(通常是64位),但并不直接指向任何具体的内存位置。`uintptr`主要用于进行指针和其他整数值之间的转换,如计算内存距离、数组长度等。由于它是无类型的,所以可以直接与其他整数类型相加减。
```go
var p *int = &i // 假设i是一个变量
fmt.Println(uintptr(p) - uintptr(&i)) // 计算p到i的距离
```
2. `unsafe.Pointer`:这实际上是`unsafe.SliceHeader`类型的别名,代表了一段内存区域的起始地址。`unsafe.Pointer`允许开发者直接操作内存,比如读取或写入内存,甚至可以在不同类型的指针间进行转换。但是,这种操作非常危险,因为它绕过了Go的垃圾回收机制和类型检查,可能导致程序崩溃或安全漏洞。
```go
import "unsafe"
p := (*int)(unsafe.Pointer(&i)) // 转换为int指针
*p = 5
```
相关问题
unsafe.pointer
`unsafe.Pointer`是Go语言中的一个指针类型,它可以存储任意类型的地址。使用`unsafe.Pointer`可以绕过Go语言的类型系统,直接操作内存,因此需要非常小心地使用。`unsafe.Pointer`可以和`uintptr`类型相互转换,可以通过`uintptr`类型进行指针运算。下面是一个使用`unsafe.Pointer`的例子:
```go
package main
import (
"fmt"
"unsafe"
)
func main() {
n := 10
b := make([]int, n)
for i := 0; i < n; i++ {
b[i] = i
}
fmt.Println(b) // [0 1 2 3 4 5 6 7 8 9]
// 取slice的最后的一个元素
end := unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + 9*unsafe.Sizeof(b[0])) // 等价于unsafe.Pointer(&b[9])
fmt.Println(*(*int)(end)) // 9
fmt.Println(uintptr(1) << (2 & (8*8 - 1))) // 4
}
```
unsafe.Pointer使用举例
下面是一个使用 `unsafe.Pointer` 进行指针类型转换的例子:
```go
package main
import (
"fmt"
"unsafe"
)
type Person struct {
Name string
Age int
}
func main() {
p := &Person{Name: "Alice", Age: 18}
// 将 *Person 转换为 uintptr
ptr := uintptr(unsafe.Pointer(p))
// 根据指针地址重新构造 Person 指针
p2 := (*Person)(unsafe.Pointer(ptr))
fmt.Printf("p2: %+v\n", p2)
}
```
在上面的例子中,首先定义了一个 `Person` 结构体类型,然后创建了一个 `Person` 类型的指针 `p`。接着,将 `p` 转换为 `uintptr` 类型,再根据指针地址重新构造 `Person` 指针 `p2`。最后,打印输出 `p2` 的值。
需要注意的是,由于 `unsafe.Pointer` 不受 Go 语言类型系统的约束,因此在使用它进行指针类型转换时需要特别小心,否则可能会导致严重的内存问题或安全问题。因此,应该尽量避免使用 `unsafe.Pointer` 进行指针类型转换,除非确实需要使用它来访问底层的内存结构或进行一些特殊的操作。
阅读全文