最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang如何使用指針靈活操作內(nèi)存及unsafe包原理解析

 更新時間:2024年07月06日 09:23:36   作者:golang架構(gòu)師k哥  
本文將深入探討unsafe包的功能和原理,同時,我們學(xué)習(xí)某種東西,一方面是為了實踐運用,另一方面則是出于功利性面試的目的,所以,本文還會為大家介紹unsafe?包的典型應(yīng)用以及高頻面試題,感興趣的朋友跟隨小編一起看看吧

Hi 你好,我是k哥。一個大廠工作6年,還在繼續(xù)搬磚的后端程序員。

我們都知道,C/C++提供了強大的萬能指針void*,任何類型的指針都可以和萬能指針相互轉(zhuǎn)換。并且指針還可以進行加減等算數(shù)操作。那么在Golang中,是否有類似的功能呢?答案是有的,這就是我們今天要探討的unsafe包。

本文將深入探討unsafe包的功能和原理。同時,我們學(xué)習(xí)某種東西,一方面是為了實踐運用,另一方面則是出于功利性面試的目的。所以,本文還會為大家介紹unsafe 包的典型應(yīng)用以及高頻面試題。

功能

為了實現(xiàn)靈活操作內(nèi)存的目的,unsafe包主要提供了4個功能:

  • 定義了Pointer類型,任何類型的指針都可和Pointer互相轉(zhuǎn)換,類似于c語言中的void*
var a int = 1
p := unsafe.Pointer(&a) // 其它類型指針轉(zhuǎn)Pointer
b := (*int)(p) // Pointer類型轉(zhuǎn)其它類型指針
fmt.Println(*b) // 輸出1
  • 定義了uintptr類型,Pointer和uintptr可以互相轉(zhuǎn)換, 從而實現(xiàn)指針的加減等算數(shù)運算。
type Person struct {
    age int
    name string
}
person := Person{age:18,name:"k哥"}
p := unsafe.Pointer(&person) // 其它類型指針轉(zhuǎn)Pointer
u := uintptr(p) // Pointer類型轉(zhuǎn)為uintptr
u=u+8 // uintptr加減操作
pName := unsafe.Pointer(u) // uintptr轉(zhuǎn)換為Pointer
name := *(*string)(pName)
fmt.Println(name) // 輸出k哥

uintptr是用于指針運算的,它只是一個存儲一個 指針地址 的 int 類型,GC 不把 uintptr 當指針,因此, uintptr 類型的目標可能會被回收

  • 獲取任意類型內(nèi)存對齊、偏移量和內(nèi)存大小。
func Alignof(x ArbitraryType) uintptr // 內(nèi)存對齊
func Offsetof(x ArbitraryType) uintptr // 內(nèi)存偏移量
func Sizeof(x ArbitraryType) uintptr // 內(nèi)存大小
  • Alignof 返回類型x的內(nèi)存地址對齊值m,這個類型在內(nèi)存中的地址必須是m的倍數(shù)(基于內(nèi)存讀寫性能的考慮)。
  • Offsetof 返回結(jié)構(gòu)體成員x在內(nèi)存中的位置離結(jié)構(gòu)體起始處(結(jié)構(gòu)體的第一個字段的偏移量都是0)的字節(jié)數(shù),即偏移量。
  • Sizeof 返回類型 x 所占據(jù)的字節(jié)數(shù),如果類型x結(jié)構(gòu)有指針,Sizeof不包含 x 指針成員所指向內(nèi)容的大小。

ArbitraryType是占位符,golang編譯器在編譯時會替換為具體類型

  • 高性能類型轉(zhuǎn)換。
func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
func SliceData(slice []ArbitraryType) *ArbitraryType
func String(ptr *byte, len IntegerType) string 
func StringData(str string) *byte
  • Slice 傳入任意類型的指針和長度,返回該類型slice變量
  • SliceData 傳入任意類型的slice變量,返回該slice底層數(shù)組的指針。
  • String 從一個byte指針派生出一個指定長度的字符串。
  • StringData 用來獲取一個字符串底層字節(jié)序列中的第一個byte的指針。

高性能類型轉(zhuǎn)換原理

為什么說Slice、SliceData、String、StringData是高性能類型轉(zhuǎn)換函數(shù)呢?下面我們就來剖析下它們的實現(xiàn)原理。

本文以String和StringData函數(shù)為例,Slice和SliceData函數(shù)實現(xiàn)原理類似。在介紹函數(shù)實現(xiàn)原理之前,先認識下string類型的底層數(shù)據(jù)結(jié)構(gòu)StringHeader。string類型會被Golang編譯器編譯成此結(jié)構(gòu),其中Data是byte數(shù)組地址,Len是字符串長度。

type StringHeader struct {
        Data uintptr // byte數(shù)組地址
        Len  int // 字符串長度
}

String函數(shù)會被Go編譯成下面的函數(shù)實現(xiàn)邏輯。我們可以發(fā)現(xiàn),ptr指針轉(zhuǎn)換為string類型,是直接將ptr賦值給StringHeader的成員Data,而不需要重新拷貝ptr指向的byte數(shù)組。從而通過零拷貝實現(xiàn)高性能類型轉(zhuǎn)換。

import (
    "fmt"
    "reflect"
    "unsafe"
)
func String(ptr *byte, len int) string {
    p := (uintptr)(unsafe.Pointer(ptr))
    hdr := &reflect.StringHeader{
        Data: p,
        Len:  len,
    }
    // 將 StringHeader 轉(zhuǎn)為 string
    str := *(*string)(unsafe.Pointer(hdr))
    return str
}
func main() {
    bytes := []byte{'h', 'e', 'l', 'l', 'o'}
    ptr := &bytes[0]
    len := 5
    str := String(ptr, len)
    fmt.Println(str) // 輸出hello
}

StringData函數(shù)會被Go編譯成下面的函數(shù)實現(xiàn)邏輯。同理,我們可以發(fā)現(xiàn),string類型轉(zhuǎn)換為byte,是直接取StringHeader的uintptr類型成員Data,并將其轉(zhuǎn)換為byte。不需要拷貝整個string,重新生成byte數(shù)組。從而通過零拷貝實現(xiàn)高性能類型轉(zhuǎn)換。

import (
    "fmt"
    "reflect"
    "unsafe"
)
func StringData(str string) *byte {
    hdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
    data := hdr.Data
    return (*byte)(unsafe.Pointer(data))
}
func main() {
    str := "hello"
    data := StringData(str)
    fmt.Println(string(*data)) // 輸出h
}

回到問題,為什么說Slice、SliceData、String、StringData是高性能類型轉(zhuǎn)換函數(shù)呢?通過String和StringData函數(shù)的實現(xiàn)邏輯,我們可以知道,String和StringData利用unsafe包,通過零拷貝,實現(xiàn)了高性能類型轉(zhuǎn)換。

典型應(yīng)用

在實踐中,常見使用unsafe包的場景有2個:

  • 與操作系統(tǒng)以及非go編寫(cgo)的代碼通信。
func SetData(bytes []byte) { 
    cstr := (*C.char)(unsafe.Pointer(&bytes[0])) // 轉(zhuǎn)換成一個C char類型
    C.setData(cstr, (C.int)(len(bytes))) // 調(diào)用C語言函數(shù)
}
  • 高性能類型轉(zhuǎn)換。
func Bytes2String(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}
func String2Bytes(s string) []byte {
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{
        Data: sh.Data,
        Len:  sh.Len,
        Cap:  sh.Len,
    }
    return *(*[]byte)(unsafe.Pointer(&bh))
}

高頻面試題

  • 能說說uintptr和unsafe.Pointer的區(qū)別嗎?
  • 字符串轉(zhuǎn)成byte數(shù)組,會發(fā)生內(nèi)存拷貝嗎?

到此這篇關(guān)于golang如何使用指針靈活操作內(nèi)存?unsafe包原理解析的文章就介紹到這了,更多相關(guān)golang unsafe包原內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Gin框架令牌桶限流實戰(zhàn)指南

    Gin框架令牌桶限流實戰(zhàn)指南

    限流是一種通過控制請求處理速率來保護系統(tǒng)的技術(shù),它能有效防止服務(wù)器因突發(fā)流量或惡意攻擊而過載,確保服務(wù)的穩(wěn)定性和可用性,本文就來介紹一下Gin 框架令牌桶限流的實現(xiàn),感興趣的可以了解一下
    2025-10-10
  • go實現(xiàn)冒泡排序的示例代碼

    go實現(xiàn)冒泡排序的示例代碼

    這篇文章主要介紹了go實現(xiàn)冒泡排序的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 利用golang實現(xiàn)pdf中自動換行的表格

    利用golang實現(xiàn)pdf中自動換行的表格

    這篇文章主要給大家介紹了如何利用golang實現(xiàn)pdf中自動換行的表格,文中通過代碼示例給大家講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • 深入詳解如何使用Go實現(xiàn)端口掃描器

    深入詳解如何使用Go實現(xiàn)端口掃描器

    這篇文章主要為大家詳細介紹了深如何使用Go語言實現(xiàn)一個簡單的端口掃描器,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-11-11
  • prometheus?client_go為應(yīng)用程序自定義監(jiān)控指標

    prometheus?client_go為應(yīng)用程序自定義監(jiān)控指標

    這篇文章主要為大家介紹了prometheus?client_go為應(yīng)用程序自定義監(jiān)控指標詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • 在Golang中實現(xiàn)定時任務(wù)的幾種高效方法

    在Golang中實現(xiàn)定時任務(wù)的幾種高效方法

    本文將詳細介紹在Golang中實現(xiàn)定時任務(wù)的幾種高效方法,包括time包中的Ticker和Timer、第三方庫cron的使用,以及基于channel和goroutine的自定義實現(xiàn),我們將通過實際代碼示例和性能分析,幫助開發(fā)者選擇最適合自己場景的定時任務(wù)解決方案,需要的朋友可以參考下
    2025-06-06
  • 使用goland調(diào)試遠程代碼的操作步驟

    使用goland調(diào)試遠程代碼的操作步驟

    大家都知道如何在goland調(diào)試遠程代碼嗎?今天小編給大家分享一篇教程幫助大家學(xué)習(xí)goland調(diào)試遠程代碼的操作步驟,感興趣的朋友跟隨小編一起看看吧
    2021-06-06
  • GO語言實現(xiàn)日志切割的示例詳解

    GO語言實現(xiàn)日志切割的示例詳解

    日志記錄對程序排查問題比較關(guān)鍵,所以本文將選擇Logrus和lumberjack兩個庫進行日志切割以及記錄調(diào)用源,感興趣的小伙伴可以了解一下
    2023-07-07
  • 基于Go語言實現(xiàn)應(yīng)用IP防火墻

    基于Go語言實現(xiàn)應(yīng)用IP防火墻

    在公司里面經(jīng)常會聽到某應(yīng)用有安全漏洞問題,沒有做安全加固,IP防火墻就是一個典型的安全加固解決方案,下面我們就來學(xué)習(xí)一下如何使用go語言實現(xiàn)IP防火墻吧
    2023-11-11
  • Go語言學(xué)習(xí)之數(shù)組的用法詳解

    Go語言學(xué)習(xí)之數(shù)組的用法詳解

    數(shù)組是相同數(shù)據(jù)類型的一組數(shù)據(jù)的集合,數(shù)組一旦定義長度不能修改,數(shù)組可以通過下標(或者叫索引)來訪問元素。本文將通過示例詳細講解Go語言中數(shù)組的使用,需要的可以參考一下
    2022-04-04

最新評論

普定县| 台南县| 泰宁县| 汤阴县| 尼勒克县| 时尚| 宜春市| 甘洛县| 建昌县| 西乌珠穆沁旗| 三亚市| 长兴县| 五指山市| 县级市| 凉城县| 正蓝旗| 视频| 巴青县| 电白县| 资阳市| 长岛县| 卓资县| 乌恰县| 平昌县| 临泉县| 元江| 巴塘县| 秭归县| 渑池县| 德清县| 吉隆县| 常山县| 遵化市| 商丘市| 库尔勒市| 喜德县| 闵行区| 云龙县| 河津市| 青岛市| 贵定县|