亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

golang利用unsafe操作未導出變量-Pointer使用詳解

2020-04-01 18:55:13
字體:
來源:轉載
供稿:網友

前言

unsafe.Pointer其實就是類似C的void *,在golang中是用于各種指針相互轉換的橋梁。uintptr是golang的內置類型,是能存儲指針的整型,uintptr的底層類型是int,它和unsafe.Pointer可相互轉換。uintptr和unsafe.Pointer的區別就是:unsafe.Pointer只是單純的通用指針類型,用于轉換不同類型指針,它不可以參與指針運算;而uintptr是用于指針運算的,GC 不把 uintptr 當指針,也就是說 uintptr 無法持有對象,uintptr類型的目標會被回收。golang的unsafe包很強大,基本上很少會去用它。它可以像C一樣去操作內存,但由于golang不支持直接進行指針運算,所以用起來稍顯麻煩。

切入正題。利用unsafe包,可操作私有變量(在golang中稱為“未導出變量”,變量名以小寫字母開始),下面是具體例子。

在$GOPATH/src下建立poit包,并在poit下建立子包p,目錄結構如下:

$GOPATH/src

----poit

--------p

------------v.go

--------main.go

以下是v.go的代碼:

package pimport ( "fmt")type V struct { i int32 j int64}func (this V) PutI() { fmt.Printf("i=%d/n", this.i)}func (this V) PutJ() { fmt.Printf("j=%d/n", this.j)}

意圖很明顯,我是想通過unsafe包來實現對V的成員i和j賦值,然后通過PutI()和PutJ()來打印觀察輸出結果。

以下是main.go源代碼:

package mainimport ( "poit/p" "unsafe")func main() { var v *p.V = new(p.V) var i *int32 = (*int32)(unsafe.Pointer(v)) *i = int32(98) var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int32(0))))) *j = int64(763) v.PutI() v.PutJ()}

當然會有些限制,比如需要知道結構體V的成員布局,要修改的成員大小以及成員的偏移量。我們的核心思想就是:結構體的成員在內存中的分配是一段連續的內存,結構體中第一個成員的地址就是這個結構體的地址,您也可以認為是相對于這個結構體偏移了0。相同的,這個結構體中的任一成員都可以相對于這個結構體的偏移來計算出它在內存中的絕對地址。

具體來講解下main方法的實現:

var v *p.V = new(p.V)

new是golang的內置方法,用來分配一段內存(會按類型的零值來清零),并返回一個指針。所以v就是類型為p.V的一個指針。

var i *int32 = (*int32)(unsafe.Pointer(v))

將指針v轉成通用指針,再轉成int32指針。這里就看到了unsafe.Pointer的作用了,您不能直接將v轉成int32類型的指針,那樣將會panic。剛才說了v的地址其實就是它的第一個成員的地址,所以這個i就很顯然指向了v的成員i,通過給i賦值就相當于給v.i賦值了,但是別忘了i只是個指針,要賦值得解引用。

*i = int32(98)

現在已經成功的改變了v的私有成員i的值,好開心_

但是對于v.j來說,怎么來得到它在內存中的地址呢?其實我們可以獲取它相對于v的偏移量(unsafe.Sizeof可以為我們做這個事),但我上面的代碼并沒有這樣去實現。各位別急,一步步來。

var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int32(0)))))

其實我們已經知道v是有兩個成員的,包括i和j,并且在定義中,i位于j的前面,而i是int32類型,也就是說i占4個字節。所以j是相對于v偏移了4個字節。您可以用uintptr(4)或uintptr(unsafe.Sizeof(int32(0)))來做這個事。unsafe.Sizeof方法用來得到一個值應該占用多少個字節空間。注意這里跟C的用法不一樣,C是直接傳入類型,而golang是傳入值。之所以轉成uintptr類型是因為需要做指針運算。v的地址加上j相對于v的偏移地址,也就得到了v.j在內存中的絕對地址,別忘了j的類型是int64,所以現在的j就是一個指向v.j的指針,接下來給它賦值:

*j = int64(763)

好吧,現在貌視一切就緒了,來打印下:

v.PutI()v.PutJ()

如果您看到了正確的輸出,那恭喜您,您做到了!

但是,別忘了上面的代碼其實是有一些問題的,您發現了嗎?

在p目錄下新建w.go文件,代碼如下:

package pimport ( "fmt" "unsafe")type W struct { b byte i int32 j int64}func init() { var w *W = new(W) fmt.Printf("size=%d/n", unsafe.Sizeof(*w))}

需要修改main.go的代碼嗎?不需要,我們只是來測試一下。w.go里定義了一個特殊方法init,它會在導入p包時自動執行,別忘了我們有在main.go里導入p包。每個包都可定義多個init方法,它們會在包被導入時自動執行(在執行main方法前被執行,通常用于初始化工作),但是,最好在一個包中只定義一個init方法,否則您或許會很難預期它的行為)。我們來看下它的輸出:

size=16

等等,好像跟我們想像的不一致。來手動計算一下:b是byte類型,占1個字節;i是int32類型,占4個字節;j是int64類型,占8個字節,1+4+8=13。這是怎么回事呢?這是因為發生了對齊。在struct中,它的對齊值是它的成員中的最大對齊值。每個成員類型都有它的對齊值,可以用unsafe.Alignof方法來計算,比如unsafe.Alignof(w.b)就可以得到b在w中的對齊值。同理,我們可以計算出w.b的對齊值是1,w.i的對齊值是4,w.j的對齊值也是4。如果您認為w.j的對齊值是8那就錯了,所以我們前面的代碼能正確執行(試想一下,如果w.j的對齊值是8,那前面的賦值代碼就有問題了。也就是說前面的賦值中,如果v.j的對齊值是8,那么v.i跟v.j之間應該有4個字節的填充。所以得到正確的對齊值是很重要的)。對齊值最小是1,這是因為存儲單元是以字節為單位。所以b就在w的首地址,而i的對齊值是4,它的存儲地址必須是4的倍數,因此,在b和i的中間有3個填充,同理j也需要對齊,但因為i和j之間不需要填充,所以w的Sizeof值應該是13+3=16。如果要通過unsafe來對w的三個私有成員賦值,b的賦值同前,而i的賦值則需要跳過3個字節,也就是計算偏移量的時候多跳過3個字節,同理j的偏移可以通過簡單的數學運算就能得到。

比如也可以通過unsafe來靈活取值:

package mainimport ( "fmt" "unsafe")func main() { var b []byte = []byte{'a', 'b', 'c'} var c *byte = &b[0] fmt.Println(*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + uintptr(1))))}

關于填充,FastCGI協議就用到了。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
伊人久久男人天堂| 亚洲色图偷窥自拍| 免费成人高清视频| 国产精品狼人色视频一区| 欧美一级电影久久| 久久久久中文字幕2018| 国产欧美精品久久久| 久久频这里精品99香蕉| 精品视频在线播放免| 亚洲精品v欧美精品v日韩精品| 欧美黑人狂野猛交老妇| 亚洲无限乱码一二三四麻| 精品国产一区二区三区久久狼黑人| 亚洲大胆美女视频| 97精品在线观看| 精品亚洲一区二区| 日韩欧美在线中文字幕| 日韩av网站在线| 日本一区二三区好的精华液| 久久久最新网址| 91精品久久久久久久| 91牛牛免费视频| 国产91九色视频| 欧美日韩国产123| 成人免费xxxxx在线观看| 中国china体内裑精亚洲片| 色综合91久久精品中文字幕| 国产精品高清在线观看| 亚洲欧美国产高清va在线播| 亚洲国产欧美一区二区三区久久| 欧美成aaa人片在线观看蜜臀| 日本不卡高字幕在线2019| 色综合久久天天综线观看| 7777精品久久久久久| 精品国产一区二区三区久久久狼| 亚洲欧美一区二区精品久久久| 国产婷婷97碰碰久久人人蜜臀| 国内精品视频在线| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产精品专区一| 久久久久国产精品一区| 91免费看片在线| 精品久久久一区二区| 久久久精品999| 成人精品aaaa网站| 2019亚洲男人天堂| 成人福利视频网| 色综合久综合久久综合久鬼88| 一区二区欧美久久| 8x海外华人永久免费日韩内陆视频| 中文字幕精品一区二区精品| 日韩av色在线| 最近免费中文字幕视频2019| 欧美日韩裸体免费视频| 在线精品91av| 国产色视频一区| 日本精品久久久| 久久久久久久久久国产| 亚洲一区999| 成人伊人精品色xxxx视频| 欧美性猛交xxxxx水多| 国产精品久久久久久婷婷天堂| 国产精品久久久久91| 欧美黄色片在线观看| 免费91在线视频| 久久久精品2019中文字幕神马| 久久久影视精品| 日韩欧美中文在线| 日韩风俗一区 二区| 国产日韩中文字幕| 最新的欧美黄色| 亚洲高清久久久久久| 亚洲石原莉奈一区二区在线观看| 日韩在线观看免费高清完整版| 亚洲a∨日韩av高清在线观看| 2019中文字幕在线免费观看| 精品久久久久人成| 性亚洲最疯狂xxxx高清| 亚洲午夜国产成人av电影男同| 国产精品黄色影片导航在线观看| 亚洲精品自拍第一页| 日韩欧美国产激情| 日韩欧美精品网址| 81精品国产乱码久久久久久| 91中文精品字幕在线视频| 国模精品视频一区二区三区| 色偷偷噜噜噜亚洲男人| 中文字幕精品网| 欧美疯狂xxxx大交乱88av| 亚洲石原莉奈一区二区在线观看| 18性欧美xxxⅹ性满足| 国产精品第2页| 国产精品久久久久免费a∨| 国产精品福利无圣光在线一区| 欧美日韩成人在线视频| 久热精品在线视频| 中文字幕不卡av| 另类天堂视频在线观看| 青青在线视频一区二区三区| 中文字幕精品一区二区精品| 亚洲第一区中文99精品| 45www国产精品网站| 欧美午夜www高清视频| 欧美日韩国产成人在线观看| 精品国产乱码久久久久久天美| 国产视频999| 日韩美女视频免费在线观看| 欧美午夜宅男影院在线观看| 欧美电影在线播放| 成人做爽爽免费视频| 亚洲综合中文字幕68页| 国产日韩在线视频| 精品免费在线视频| 国产精品1234| 91欧美激情另类亚洲| 久久精品2019中文字幕| 亚洲欧洲午夜一线一品| 亚洲精品日韩丝袜精品| 亚洲一区二区精品| 国产精品国产自产拍高清av水多| 裸体女人亚洲精品一区| www.精品av.com| 久久在精品线影院精品国产| 亚洲精品久久久久中文字幕二区| 国内精品400部情侣激情| 国产丝袜视频一区| 日韩欧美亚洲综合| 欧美激情在线有限公司| 日韩最新在线视频| 主播福利视频一区| 久久久91精品国产一区不卡| 国产一区二区三区高清在线观看| 91精品国产免费久久久久久| 欧日韩不卡在线视频| 国产精品久久久久久久久久久久久| 亚洲第一区在线观看| 岛国精品视频在线播放| 浅井舞香一区二区| 久久国产精品久久久| 亚洲精品国产综合久久| 久久视频免费观看| 欧美黄色小视频| 神马久久桃色视频| 91精品国产自产在线| 91精品成人久久| 国内精品小视频| 8x拔播拔播x8国产精品| 亚洲片在线资源| 久久精品电影网| 综合欧美国产视频二区| 国产一区二区三区精品久久久| 日韩精品日韩在线观看| 日日噜噜噜夜夜爽亚洲精品| 色综合久久久久久中文网| 亚洲午夜久久久影院| 另类视频在线观看| 一本大道香蕉久在线播放29| 久热精品视频在线| 欧美大尺度电影在线观看| 亚洲欧洲一区二区三区久久| 在线亚洲欧美视频| 久99九色视频在线观看| 国产成人精品优优av| 国产精品国模在线|