Golang unsafe包使用

unsafe包提供了訪問底層內(nèi)存的方法。是用unsafe函數(shù)可以提高訪問對(duì)象的速度慕趴。通常用于對(duì)大數(shù)組的遍歷痪蝇。

unsafe內(nèi)容介紹

func Alignof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Sizeof(x ArbitraryType) uintptr
type ArbitraryType int
type Pointer *ArbitraryType
  • 通過指針加偏移量的操作鄙陡,在地址中,修改霹俺,訪問變量的值

這個(gè)包中柔吼,只提供了3個(gè)函數(shù),兩個(gè)類型

unsafe中丙唧,通過這兩個(gè)個(gè)兼容萬物的類型,將其他類型都轉(zhuǎn)換過來觅玻,然后通過這三個(gè)函數(shù),分別能取長(zhǎng)度溪厘,偏移量畸悬,對(duì)齊字節(jié)數(shù),就可以在內(nèi)存地址映射中披粟,來回游走守屉。放在c語言中拇泛,是不是思灌,只要給你一個(gè)起始地址泰偿,你就一下子干到底L鹧佟!牍氛!在golang中搬俊,通過unsafe包,你也可以盡情的去放縱

uintptr:用于指針運(yùn)算餐屎,GC 不把 uintptr 當(dāng)指針腹缩,uintptr 無法持有對(duì)象藏鹊。uintptr 類型的目標(biāo)會(huì)被回收盘寡。

unsafe.Pointer 可以和 普通指針 進(jìn)行相互轉(zhuǎn)換撮慨。

unsafe.Pointer 可以和 uintptr 進(jìn)行相互轉(zhuǎn)換砌溺。

也就是說 unsafe.Pointer 是橋梁抚吠,可以讓任意類型的指針實(shí)現(xiàn)相互轉(zhuǎn)換楷力,也可以將任意類型的指針轉(zhuǎn)換為 uintptr 進(jìn)行指針運(yùn)算萧朝。

詳細(xì)說明

  • type ArbitraryType int

是int的一個(gè)別名检柬,但是golang中何址,對(duì)ArbitraryType賦予了特殊的意義,

  • type Pointer *ArbitraryType

是int指針類型的一個(gè)別名原押,在golang系統(tǒng)中诸衔,可以把Pointer類型笨农,理解成任何指針的親爹。

  • func Alignof(x ArbitraryType) uintptr

Alignof返回變量對(duì)齊字節(jié)數(shù)量

  • func Offsetof(x ArbitraryType) uintptr

Offsetof返回變量指定屬性的偏移量雨膨,這個(gè)函數(shù)雖然接收的是任何類型的變量幢泼,但是這個(gè)又一個(gè)前提脾还,就是變量要是一個(gè)struct類型鄙漏,且還不能直接將這個(gè)struct類型的變量當(dāng)作參數(shù)怔蚌,只能將這個(gè)struct類型變量的屬性當(dāng)作參數(shù)旁赊。

  • func Sizeof(x ArbitraryType) uintptr

Sizeof 返回變量在內(nèi)存中占用的字節(jié)數(shù)籍胯,切記离福,如果是slice妖爷,則不會(huì)返回這個(gè)slice在內(nèi)存中的實(shí)際占用長(zhǎng)度絮识。

示例

通過指針修改結(jié)構(gòu)體字段

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    s := struct {
        a byte
        b byte
        c byte
        d int64
    }{0, 0, 0, 0}

    // 將結(jié)構(gòu)體指針轉(zhuǎn)換為通用指針
    p := unsafe.Pointer(&s)
    // 保存結(jié)構(gòu)體的地址備用(偏移量為 0)
    up0 := uintptr(p)
    // 將通用指針轉(zhuǎn)換為 byte 型指針
    pb := (*byte)(p)
    // 給轉(zhuǎn)換后的指針賦值
    *pb = 10
    // 結(jié)構(gòu)體內(nèi)容跟著改變
    fmt.Println(s)

    // 偏移到第 2 個(gè)字段
    up := up0 + unsafe.Offsetof(s.b)
    // 將偏移后的地址轉(zhuǎn)換為通用指針
    p = unsafe.Pointer(up)
    // 將通用指針轉(zhuǎn)換為 byte 型指針
    pb = (*byte)(p)
    // 給轉(zhuǎn)換后的指針賦值
    *pb = 20
    // 結(jié)構(gòu)體內(nèi)容跟著改變
    fmt.Println(s)

    // 偏移到第 3 個(gè)字段
    up = up0 + unsafe.Offsetof(s.c)
    // 將偏移后的地址轉(zhuǎn)換為通用指針
    p = unsafe.Pointer(up)
    // 將通用指針轉(zhuǎn)換為 byte 型指針
    pb = (*byte)(p)
    // 給轉(zhuǎn)換后的指針賦值
    *pb = 30
    // 結(jié)構(gòu)體內(nèi)容跟著改變
    fmt.Println(s)

    // 偏移到第 4 個(gè)字段
    up = up0 + unsafe.Offsetof(s.d)
    // 將偏移后的地址轉(zhuǎn)換為通用指針
    p = unsafe.Pointer(up)
    // 將通用指針轉(zhuǎn)換為 int64 型指針
    pi := (*int64)(p)
    // 給轉(zhuǎn)換后的指針賦值
    *pi = 40
    // 結(jié)構(gòu)體內(nèi)容跟著改變
    fmt.Println(s)
}

訪問數(shù)組

package main

import (
     "fmt"
     "unsafe"
)

type Foo struct {
     A int
     B int
}

func main() {
     foo := &Foo{1, 2}
     fmt.Println(foo)

     base := uintptr(unsafe.Pointer(foo))
     offset := unsafe.Offsetof(foo.A)

     ptr := unsafe.Pointer(base + offset)
     *(*int)(ptr) = 3

     fmt.Println(foo)
}

修改其它包中的結(jié)構(gòu)體私有字段

方法A(指針遍歷)

package main

import (
    "fmt"
    "reflect"
    "strings"
    "unsafe"
)

func main() {
    // 創(chuàng)建一個(gè) strings 包中的 Reader 對(duì)象
    // 它有三個(gè)私有字段:s string、i int64鲜屏、prevRune int
    sr := strings.NewReader("abcdef")
    // 此時(shí) sr 中的成員是無法修改的
    fmt.Println(sr)
    // 但是我們可以通過 unsafe 來進(jìn)行修改
    // 先將其轉(zhuǎn)換為通用指針
    p := unsafe.Pointer(sr)
    // 獲取結(jié)構(gòu)體地址
    up0 := uintptr(p)
    // 確定要修改的字段(這里不能用 unsafe.Offsetof 獲取偏移量洛史,因?yàn)槭撬接凶侄危?    if sf, ok := reflect.TypeOf(*sr).FieldByName("i"); ok {
        // 偏移到指定字段的地址
        up := up0 + sf.Offset
        // 轉(zhuǎn)換為通用指針
        p = unsafe.Pointer(up)
        // 轉(zhuǎn)換為相應(yīng)類型的指針
        pi := (*int64)(p)
        // 對(duì)指針?biāo)赶虻膬?nèi)容進(jìn)行修改
        *pi = 3 // 修改索引
    }
    // 看看修改結(jié)果
    fmt.Println(sr)
    // 看看讀出的是什么
    b, err := sr.ReadByte()
    fmt.Printf("%c, %v\n", b, err)
}

方法B(類型轉(zhuǎn)換)

// 定義一個(gè)和 strings 包中的 Reader 相同的本地結(jié)構(gòu)體
type Reader struct {
    s        string
    i        int64
    prevRune int
}

func main() {
    // 創(chuàng)建一個(gè) strings 包中的 Reader 對(duì)象
    sr := strings.NewReader("abcdef")
    // 此時(shí) sr 中的成員是無法修改的
    fmt.Println(sr)
    // 我們可以通過 unsafe 來進(jìn)行修改
    // 先將其轉(zhuǎn)換為通用指針
    p := unsafe.Pointer(sr)
    // 再轉(zhuǎn)換為本地 Reader 結(jié)構(gòu)體
    pR := (*Reader)(p)
    // 這樣就可以自由修改 sr 中的私有成員了
    (*pR).i = 3 // 修改索引
    // 看看修改結(jié)果
    fmt.Println(sr)
    // 看看讀出的是什么
    b, err := sr.ReadByte()
    fmt.Printf("%c, %v\n", b, err)
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市己儒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绩卤,老刑警劉巖濒憋,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裆站,死亡現(xiàn)場(chǎng)離奇詭異宏胯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扣草,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛙婴,“玉大人街图,你說我怎么就攤上這事餐济⌒跄罚” “怎么了蚁阳?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)归粉。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么靖苇? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任埠忘,我火速辦了婚禮名船,結(jié)果婚禮上旨怠,老公的妹妹穿的比我還像新娘百揭。我一直安慰自己,他們只是感情好瓮床,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布盹舞。 她就那樣靜靜地躺著,像睡著了一般隘庄。 火紅的嫁衣襯著肌膚如雪踢步。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天丑掺,我揣著相機(jī)與錄音获印,去河邊找鬼。 笑死街州,一個(gè)胖子當(dāng)著我的面吹牛兼丰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唆缴,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鳍征,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了面徽?” 一聲冷哼從身側(cè)響起艳丛,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎趟紊,沒想到半個(gè)月后氮双,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡霎匈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年戴差,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铛嘱。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡暖释,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弄痹,到底是詐尸還是另有隱情饭入,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布肛真,位于F島的核電站谐丢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乾忱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一讥珍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窄瘟,春花似錦衷佃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至图云,卻和暖如春惯悠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背竣况。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工克婶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丹泉。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓情萤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親摹恨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筋岛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容