亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言普通指針unsafe.Pointer?uintpt之間的關(guān)系及指針運(yùn)算

 更新時間:2023年12月18日 10:59:15   作者:菜皮日記  
這篇文章主要為大家介紹了Go語言普通指針unsafe.Pointer?uintpt之間的關(guān)系及指針運(yùn)算示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

C 語言指針運(yùn)算

指針運(yùn)算就是對指針類型的變量做常規(guī)數(shù)學(xué)運(yùn)算,例如加減操作,實(shí)現(xiàn)地址的偏移。指針運(yùn)算在 C 語言中是原生支持的,可以直接在指針變量上做加減,例如:

#include <stdio.h>
const int MAX = 3;
int main ()
{
   int  var[] = {10, 100, 200};
   int  i, *ptr;
   /* 指針中的數(shù)組地址 */
   ptr = var;
   for ( i = 0; i < MAX; i++)
   {
      printf("存儲地址:var[%d] = %p\n", i, ptr );
      printf("存儲值:var[%d] = %d\n", i, *ptr );
      /* 直接對指針做++操作,指向下一個位置 */
      ptr++;
   }
   return 0;
}

結(jié)果

存儲地址:var[0] = e4a298cc
存儲值:var[0] = 10
存儲地址:var[1] = e4a298d0
存儲值:var[1] = 100
存儲地址:var[2] = e4a298d4
存儲值:var[2] = 200

C 語言指針運(yùn)算猶如一把雙刃劍,使用得當(dāng)會起到事半功倍,有神之一手的效果,反之則會產(chǎn)生意想不到的 bug 而且很難排查。因?yàn)樵谧鲋羔樳\(yùn)算時是比較抽象的,具體偏移了多少之后指向到了哪里是非常不直觀的,可能已經(jīng)偏離了設(shè)想中的位置而沒有發(fā)現(xiàn),運(yùn)行起來就會出現(xiàn)錯誤。

找出數(shù)組中最小的元素

例如這段 C 代碼,找出數(shù)組中最小的元素:

#include <stdio.h>
int findMin(int *arr, int length) {
    int min = *arr;
    for (int i = 0; i <= length; i++) {  // 注意這里是 i <= length,而不是 i < length
        printf("i=%d v=%d\n", i, *(arr+i));
        if (*(arr + i) < min) {
            min = *(arr + i);
        }
    }
    return min;
}
int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int length = sizeof(arr) / sizeof(arr[0]);
    printf("Min value is: %d\n", findMin(arr, length));
    return 0;
}

數(shù)組中最小的是 1,可結(jié)果卻是 0:

i=0 v=1
i=1 v=2
i=2 v=3
i=3 v=4
i=4 v=5
i=5 v=0
Min value is: 0

這是由于在 findMin 函數(shù)中循環(huán)條件是 i ≤ length ,超出數(shù)組大小多循環(huán)了一次,實(shí)際上數(shù)組已經(jīng)越界,而 C 語言的數(shù)組實(shí)際上就是指針,C 運(yùn)行時認(rèn)為這是在指針運(yùn)算,所以不會報錯,導(dǎo)致數(shù)組訪問到了其他內(nèi)存地址,最終得到了一個錯誤結(jié)果。

事實(shí)上有很多病毒和外掛的原理就是利用指針來訪問并修改程序運(yùn)行時內(nèi)存數(shù)據(jù)來達(dá)到目的。例如游戲外掛可能會搜索和修改內(nèi)存中的特定值,以改變玩家的生命值、金錢或其他游戲?qū)傩?。通過指針運(yùn)算,外掛可以直接訪問這些內(nèi)存位置并對其進(jìn)行修改。而病毒可能使用指針運(yùn)算來插入其自己的代碼到一個運(yùn)行中的程序,或者篡改程序的正??刂屏?,以達(dá)到其惡意目的。

在 C 語言之后的很多語言多多少少都對指針做了限制,例如 PHP 中的引用就可以看做是指針的簡化版,而 Java 甚至干脆移除了指針。

Go 指針運(yùn)算

對指針做加法會報錯

在 Go 中默認(rèn)的普通指針也是指代的是一個內(nèi)存地址,值類似 0x140000ac008,但 Go 的普通指針不支持指針運(yùn)算的,例如對指針做加法會報錯:

a := 10
var p *int = &amp;a
p = p + 1

報錯

invalid operation: p + 1 (mismatched types *int and untyped int)

但 Go 還是提供了一種直接操作指針的方式,就是 unsafe.Pointer 和 uintptr。

uintptr 是一個整型,可理解為是將內(nèi)存地址轉(zhuǎn)換成了一個整數(shù),既然是一個整數(shù),就可以對其做數(shù)值計算,實(shí)現(xiàn)指針地址的加減,也就是地址偏移,類似跟 C 語言中一樣的效果。

而 unsafe.Pointer 是普通指針和 uintptr 之間的橋梁,通過 unsafe.Pointer 實(shí)現(xiàn)三者的相互轉(zhuǎn)換。

*T <-> unsafe.Pointer <-> uintptr

先看看這三位都長什么樣:

func main() {
    a := 10
    var b *int
    b = &a
    fmt.Printf("a is %T, a=%v\n", a, a)
    fmt.Printf("b is %T, b=%v\n", b, b)
    p := unsafe.Pointer(b)
    fmt.Printf("p is %T, p=%v\n", p, p)
    uptr := uintptr(p)
    fmt.Printf("uptr is %T, uptr=%v\n", uptr, uptr)
}

輸出

a is int, a=10
b is *int, b=0x140000ae008
p is unsafe.Pointer, p=0x140000ae008
uptr is uintptr, uptr=1374390247432

舉一個通過指針運(yùn)算修改結(jié)構(gòu)體的例子

type People struct {
    age    int32
    height int64
    name   string
}
people := &People{}
fmt.Println(people)
// 將 people 普通指針轉(zhuǎn)成 unsafe.Pointer 再轉(zhuǎn)為 uintptr
// 后面再加上 height 字段相對于結(jié)構(gòu)體本身的偏移量,就得到了 height 的地址的 uintptr 值
// 再將 height 的 uintptr 值轉(zhuǎn)成 unsafe.Pointer 賦值給 height 變量
// 所以現(xiàn)在 height 的類型是 unsafe.Pointer
height := unsafe.Pointer(uintptr(unsafe.Pointer(people)) + unsafe.Offsetof(people.height))
fmt.Printf("people addr is %v\n", unsafe.Pointer(people))
fmt.Printf("height is %T\n", height)
fmt.Printf("height addr is %v\n", height)
println("---")
// 使用類型轉(zhuǎn)換,將 unsafe.Pointer 類型的 height 轉(zhuǎn)換成 *int 指針
// 再通過最前面的 * 解引用,修改其值 身高2米26
*((*int)(height)) = 226
fmt.Println(people)
// 同樣的操作可以修改年齡和名字
age := unsafe.Pointer(uintptr(unsafe.Pointer(people)) + unsafe.Offsetof(people.age))
*((*int)(age)) = 18
name := unsafe.Pointer(uintptr(unsafe.Pointer(people)) + unsafe.Offsetof(people.name))
*((*string)(name)) = "小明"
fmt.Println(people)

輸出

people: &{0 0 }
people addr is 0x1400005e020
height is unsafe.Pointer
height addr is 0x1400005e028
---
people: &{0 226 }
people: &{18 226 }
people: &{18 226 小明}

通過指針轉(zhuǎn)換將一個字節(jié)切片轉(zhuǎn)成浮點(diǎn)數(shù)組

再看一個操作,通過指針轉(zhuǎn)換,將一個字節(jié)切片轉(zhuǎn)成浮點(diǎn)數(shù)組:

package main
import (
    "fmt"
    "unsafe"
)
func main() {
    // 假設(shè)我們有一個字節(jié)切片,并且我們知道它是由浮點(diǎn)數(shù)表示的
    byteSlice := []byte{0, 0, 0, 0, 0, 0, 240, 63} // 1.0 的 IEEE-754 表示
    // 使用 unsafe 把字節(jié)切片轉(zhuǎn)換為浮點(diǎn)數(shù)切片
    floatSlice := (*[1]float64)(unsafe.Pointer(&byteSlice[0]))
    fmt.Println(floatSlice)
}

輸出

&[1]

這個過程不需要 Go 的類型檢查,繞過了很多流程,相對來說性能會更高。

所以大體上通過 unsafe.Pointer 的指針運(yùn)算會應(yīng)用在如下幾個方面:

  • 性能優(yōu)化: 當(dāng)性能是關(guān)鍵因素時,unsafe 可以用來避免一些開銷。例如,通過直接操作內(nèi)存,可以避免切片或數(shù)組的額外分配和復(fù)制。
  • C 語言交互: 當(dāng)使用 cgo 與 C 語言庫交互時,unsafe 包通常用于轉(zhuǎn)換類型和指針。
  • 自定義序列化/反序列化: 在自定義的序列化或反序列化邏輯中,unsafe 可以用于直接訪問結(jié)構(gòu)的內(nèi)存布局,可以提高性能。
  • 實(shí)現(xiàn)非標(biāo)準(zhǔn)的數(shù)據(jù)結(jié)構(gòu): 有時,特定的問題需要非標(biāo)準(zhǔn)的數(shù)據(jù)結(jié)構(gòu)。unsafe 允許你直接操作內(nèi)存,可以用來實(shí)現(xiàn)一些 Go 的標(biāo)準(zhǔn)庫中沒有的數(shù)據(jù)結(jié)構(gòu)。
  • 反射: 與反射結(jié)合時,unsafe 可以用于訪問結(jié)構(gòu)體的私有字段。

以上就是Go語言普通指針unsafe.Pointer uintpt之間的關(guān)系及指針運(yùn)算的詳細(xì)內(nèi)容,更多關(guān)于Go普通指針unsafe.Pointer uintptr的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go模板template用法詳解

    Go模板template用法詳解

    這篇文章主要介紹了Go標(biāo)準(zhǔn)庫template模板用法詳解;包括GO模板注釋,作用域,語法,函數(shù)等知識,需要的朋友可以參考下
    2022-04-04
  • 使用Golang實(shí)現(xiàn)對網(wǎng)絡(luò)數(shù)據(jù)包的捕獲與分析

    使用Golang實(shí)現(xiàn)對網(wǎng)絡(luò)數(shù)據(jù)包的捕獲與分析

    在網(wǎng)絡(luò)通信中,網(wǎng)絡(luò)數(shù)據(jù)包是信息傳遞的基本單位,抓包是一種監(jiān)控和分析網(wǎng)絡(luò)流量的方法,用于獲取網(wǎng)絡(luò)數(shù)據(jù)包并對其進(jìn)行分析,本文將介紹如何使用Golang實(shí)現(xiàn)抓包功能,包括網(wǎng)絡(luò)數(shù)據(jù)包捕獲和數(shù)據(jù)包分析,需要的朋友可以參考下
    2023-11-11
  • Golang應(yīng)用程序性能優(yōu)化技巧分享

    Golang應(yīng)用程序性能優(yōu)化技巧分享

    隨著科技的進(jìn)步,人人都想要快速的應(yīng)用,這就需要優(yōu)化您的應(yīng)用程序性能。本文為大家整理了一些Golang應(yīng)用程序性能優(yōu)化的技巧,希望對大家有所幫助
    2023-04-04
  • golang類型轉(zhuǎn)換之interface轉(zhuǎn)字符串string簡單示例

    golang類型轉(zhuǎn)換之interface轉(zhuǎn)字符串string簡單示例

    在我們使用Golang進(jìn)行開發(fā)過程中,總是繞不開對字符或字符串的處理,這篇文章主要給大家介紹了關(guān)于golang類型轉(zhuǎn)換之interface轉(zhuǎn)字符串string的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Gin的中間件執(zhí)行流程與用法詳解

    Gin的中間件執(zhí)行流程與用法詳解

    我們在使用Gin框架進(jìn)行Web開發(fā)的時候,基本上都會遇到登錄攔截的場景,在Gin當(dāng)中,?中間件和業(yè)務(wù)處理函數(shù)都是一樣的類型,都是一種函數(shù),本文給大家介紹了Gin的中間件執(zhí)行流程與用法,需要的朋友可以參考下
    2024-04-04
  • Go 代碼生成工具詳解

    Go 代碼生成工具詳解

    這篇文章主要介紹了Go 代碼生成工具詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Go語言基礎(chǔ)函數(shù)包的使用學(xué)習(xí)

    Go語言基礎(chǔ)函數(shù)包的使用學(xué)習(xí)

    本文通過一個實(shí)現(xiàn)加減乘除運(yùn)算的小程序來介紹go函數(shù)的使用,以及使用函數(shù)的注意事項(xiàng),并引出了對包的了解和使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • golang中一種不常見的switch語句寫法示例詳解

    golang中一種不常見的switch語句寫法示例詳解

    這篇文章主要介紹了golang中一種不常見的switch語句寫法,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • Go map發(fā)生內(nèi)存泄漏解決方法

    Go map發(fā)生內(nèi)存泄漏解決方法

    這篇文章主要介紹了Go map發(fā)生內(nèi)存泄漏解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • goFrame的隊(duì)列g(shù)queue對比channel使用詳解

    goFrame的隊(duì)列g(shù)queue對比channel使用詳解

    這篇文章主要為大家介紹了goFrame的gqueue對比channel使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06

最新評論