Go?指針、uintptr、unsafe.Pointer之間如何轉換
普通指針(*T)
普通指針類型,用于傳遞對象地址,不能進行指針運算
a := 10 var b *int //int類型指針 b = &a fmt.Println("a=", a) // a=10 fmt.Println("b=", b) // b=0xc000225530 輸出的是a的地址 fmt.Println("c=", *b) // c=10 對a的地址進行取值
uintptr
uintptr是一個無符號的整型,它可以保存一個指針地址,它可以進行指針運算。想取值需要轉成unsafe.Pointer后, 需再轉到相對應的指針類型。
源代碼中的定義如下。
package builtin //uintptr is an integer type that is large enough to hold the bit pattern of any pointer. //uintptr是一個能足夠容納指針位數大小的整數類型 type uintptr uintptr
unsafe.Pointer
unsafe.Pointer功能介紹
unsafe.Pointer定義如下,可以指向任意類型的int指針。不能進行指針運算,不能讀取內存存儲的值(想讀取的話需要轉成相對應類型的指針)。
它是橋梁,讓任意類型的指針實現相互轉換, 也可以轉換成uintptr 進行指針運算。
type Pointer *ArbitraryType type ArbitraryType int
unsafe.Pointer作為橋梁實現相互轉換
unsafe.Pointer在unsafe包中還有以下幾個函數在我們計算可能會用到
==unsafe包的幾個函數== //返回一個變量占用的內存字節(jié)數 func Sizeof(x ArbitraryType) uintptr //返回結構體某個字段的地址相對于此結構體起始地址的偏移量 func Offsetof(x ArbitraryType) uintptr //返回對齊系數 func Alignof(x ArbitraryType) uintptr
指針和unsafe.Pointer的轉換
舉些栗子:
a := int64(100) var ptr *int ptr = (*int)(unsafe.Pointer(&a)) fmt.Printf("%d\n", *ptr) //輸出100 如果是int32輸出一個很大值
這是個將int64轉換為int的場景,如果是int32的話轉換起來會出問題,因為存在轉換后的類型大于轉換前的類型。
如果是結構體的話,我們可以用到unsafe.Offsetof函數來計算
type People struct { age int32 height int64 } var p = &People height := unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Offsetof(p.height)) *((*int)(height)) = 100 //將height的值改為100 //uintptr(unsafe.Pointer(p)) 獲取了 w 的指針起始值 //unsafe.Offsetof(w.p) 獲取 b 變量的偏移量
uintptr和unsafe.Pointer的轉換
同樣舉個栗子,結合上面的People結構體的操作,對unsafe.Pointer和uintptr的轉換做一個詳細的說明,對加深理解非常清晰明了。
var p = &People height := unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Offsetof(p.height)) *((*int)(height)) = 100 //將height的值改為100
上面的代碼可以理解為以下步驟:
- 要想修改People結構體的height的值,首先unsafe.Pointer(p),轉換為uintptr
- 通過unsafe.Offsetof獲取height的偏移量,兩者都是uintptr,可進行運算得到height的地址
- unsafe.Pointer將height的地址轉為uintptr
- 先轉為*int指針,然后獲得height的值并賦值100
總結
指針、uintptr、unsafe.Pointer之間的轉換有點繞,相信看完這個會對這個有一個非常清晰的了解。大家可以動手試試
到此這篇關于Go 指針、uintptr、unsafe.Pointer之間如何轉換的文章就介紹到這了,更多相關Go 指針 uintptr unsafe.Pointer內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!