go uintptr unsafe Pointer offset() 的使用
go語言基本類型
| 類型名稱 | 有無符號 | 占用位數 |
| int8 | Yes | 8 |
| int16 | Yes | 16 |
| int32 | Yes | 32 |
| int64 | yes | 64 |
| uint8 | No | 8 |
| uint16 | No | 16 |
| uint32 | No | 32 |
| uint64 | No | 64 |
| int | Yes | 32或64,等于cpu位數 |
| uint | No | 32或64,等于cpu位數 |
| rune | No | 32,與uint32等價 |
| byte | No | 8,與uint8等價 |
| uintptr | No | 64,與uint64等價 |
?
?
?
?
?
?
?
?
?
?
?
?
?
?
rune?類型是 Unicode 字符類型,和 uint32 類型等價,通常用于表示一個 Unicode 字符。rune 和 uint32 可以互換使用。
byte?類型與uint8類型等價,byte類型一般用于強調數值是一個原始的內存數據而不是 一個小的整數。
uintptr?是一種無符號的整數類型,與uint64等價,范圍:0 ~ 18446744073709551615,足以容納任何指針值轉換來的整型值。 uintptr類型只有在底層編程是才需要,特別是Go語言和C語言函數庫或操作系統接口相交互的地方。GC 不把 uintptr 當指針,uintptr 無法持有對象。uintptr 類型的目標會被回收,所以不要聲明uintptr類型的變量
不管它們的具體大小,int、uint和uintptr是不同類型的兄弟類型。其中int和int32也是 不同的類型, 即使int的大小也是32bit,在需要將int當作int32類型的地方需要一個顯式的類型轉換操作,反之亦然
unsafe.Pointer
一個可以指向任意類型的指針,不可以進行數值計算
有四種區別于其他類型的特殊操作:
1. 任意類型的指針值均可轉換為 Pointer
2. Pointer 均可轉換為任意類型的指針值
3. uintptr 均可轉換為 Pointer
4. Pointer 均可轉換為 uintptr
unsafe 庫讓 golang 可以像C語言一樣操作計算機內存,但這并不是golang推薦使用的,能不用盡量不用,就像它的名字所表達的一樣,它繞過了golang的內存安全原則,是不安全的,容易使你的程序出現莫名其妙的問題,不利于程序的擴展與維護
?
示例1(unsafe.Pointer用來取地址,uintptr用來取地址的10進制數值):
package main import ("fmt""unsafe" ) func main() {a := int(5)p := &afmt.Println("p:", p) // a的地址,16進制形式fmt.Println("unsafe.Pointer(&a):", unsafe.Pointer(&a)) // a的地址,16進制形式fmt.Println("uintptr(unsafe.Pointer(&a)):", uintptr(unsafe.Pointer(&a))) // a的地址,10進制形式 }結果如下圖:
PS:每次運行a的地址可能是不同的,但?unsafe.Pointer(&a) 和?uintptr(unsafe.Pointer(&a))的值是一樣的,只是前者是指針類型,16進制,后者是整數類型,10進制,兩者相等,這里 0xc00000a0b8,轉換為10進制即 824633761976
示例2(地址計算,偏移,并修改)
package main import ("fmt""unsafe" ) func main() {a := [4]int{0, 1, 2, 3}p1 := unsafe.Pointer(&a[1]) // p1指向a[1]的起始地址// a[1]的地址類型轉換為uintptr類型,后移2個元素的位置,這樣移動到a[3]的起始地址位置p3 := unsafe.Pointer(uintptr(p1) + 2 * unsafe.Sizeof(a[0]))*(*int)(p3) = 6 // 先將Pointer類型轉換為*int類型,再賦值fmt.Println("a =", a) // 打印出來結果是:a = [0 1 2 6] }結果如下圖:
PS:unsafe.Pointer 是橋梁,可以讓任意類型的指針實現相互轉換,也可以將任意類型的指針轉換為 uintptr 進行指針運算
示例3(unsafe.Offsetof的使用)
該函數返回屬性x的起始地址和結構體起始地址的字節數
func Offsetof(x ArbitraryType) uintptr
代碼如下:
package main import ("fmt""unsafe" ) type Person struct {name stringage intgender bool } func main() {john := Person{"John", 30, true}pp := unsafe.Pointer(&john) // 結構體的起始地址pname := (*string)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.name))) // 屬性name的起始地址,轉換為*string類型page := (*int)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.age))) // 屬性age的起始地址,轉換為*int類型pgender := (*bool)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.gender))) // 屬性gender的起始地址,轉換為*bool類型// 進行賦值*pname = "Alice"*page = 28*pgender = falsefmt.Println(john) // {Alice 28 false} }實驗結果如下:
總結
以上是生活随笔為你收集整理的go uintptr unsafe Pointer offset() 的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: go WaitGroup的坑
- 下一篇: go sync.WaitGroup源码分