首頁>技術>

上一篇文章介紹了rust 的unsafe的使用,突然想起來go 裡面也有類似的unsafe 裸指標操作。也是透過unsafe的package。先看一個demo

//定義一個結構體,包含一個string和int64type Test struct {	str string	num int64}func main() {	t := Test{str: "hello", num: 1}	tp := unsafe.Pointer(&t) //獲取物件的通用指標	tsp := (*string)(tp) //將通用指標轉化為字串型別的指標	*tsp = "world" //修改指標的內容	tip := (*int64)(unsafe.Pointer(uintptr(tp) + unsafe.Offsetof(t.num))) //獲取num的地址,並轉化為int64指標	*tip = 2 //修改num的值	fmt.Printf("t.str: %s, t.num: %d", t.str, t.num)}

上面程式輸出的內容是

t.str: world, t.num: 2

可以順利透過指標修改底層資料。我們看一下test底層資料結構

test 有兩個部分組成,一個是字串的指標,一個是num,其中字串的記憶體結構是

type StringHeader struct {  Data uintptr  Len  int}

那麼整個記憶體的佈局就是

可以看到tp 指標指向了結構體的地址,當把tp 轉化為字串指標的時候,相當於把整個Test 結構體轉化為字串了,於是便可以修改字串的內容了。後續修改num的原理也是類似的。但這種操作並非一直安全,看下面的例子

type Test struct {	age uint8	num uint8}func main() {	t := Test{age: 2, num: 10}	tp := unsafe.Pointer(&t)	tsp := (*int64)(tp) //強行轉化為int64	*tsp = 40000	fmt.Printf("t.age: %d, t.num: %d", t.age, t.num)}

你們先猜一下這個程式輸出的結果

公佈答案

t.age: 64, t.num: 156

可以看到對age 的賦值影響了num。因為他們在內的排布是連續的,如果將age 轉化為int64,那麼它會擴充套件到num的記憶體空間,當賦值age 的時候自然會影響到num了。

所以這就是為啥這個包的名字叫做unsafe,它代表不安全的記憶體操作了,需要開發者自己去保證。

7
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • C語言程式設計:函式指標陣列和函式指標陣列指標的詳解