<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] ## 概述 最近在鞏固cgo的基礎知識,在網上看到一篇Go和C之間 字符串數組、切片類型轉換的文章,讓我想到我之前寫的一篇在[go中遍歷C結構體數組](https://blog.csdn.net/qq_39503880/article/details/112478609)的文章,讓我有新的方法來解決之前的問題,把C的數組轉化為Go的切片,對于文章的方法我直接”拿來主義“。 ## 數組、字符串和切片 我們將一段特定長度的內存統稱為數組。C語言的字符串是一個char類型的數組,字符串的長度需要根據表示結尾的NULL字符的位置確定。C語言中沒有切片類型。 在Go語言中,數組是一種值類型,而且數組的長度是數組類型的一個部分。Go語言字符串對應一段長度確定的只讀byte類型的內存。Go語言的切片則是一個簡化版的動態數組。 Go語言和C語言的數組、字符串和切片之間的相互轉換可以簡化為Go語言的切片和C語言中指向一定長度內存的指針之間的轉換。 ## 以克隆的方式進行類型轉換 CGO的C虛擬包提供了以下一組函數,用于Go語言和C語言之間數組和字符串的雙向轉換: ```go func C.CString(string) *C.char //go字符串轉化為char* func C.CBytes([]byte) unsafe.Pointer // go 切片轉化為指針 func C.GoString(*C.char) string //C字符串 轉化為 go字符串 func C.GoStringN(*C.char, C.int) string func C.GoBytes(unsafe.Pointer, C.int) []byte ``` **其中`C.CString`針對輸入的Go字符串,克隆一個C語言格式的字符串;返回的字符串由C語言的`malloc`函數分配,不使用時需要通過C語言的`free`函數釋放。**`C.CBytes`函數的功能和`C.CString`類似,用于從輸入的Go語言字節切片克隆一個C語言版本的字節數組,同樣返回的數組需要在合適的時候釋放。**`C.GoString`用于將從NULL結尾的C語言字符串克隆一個Go語言字符串。**`C.GoStringN`是另一個字符數組克隆函數。`C.GoBytes`用于從C語言數組,克隆一個Go語言字節切片。 >克隆方式實現轉換的優點是接口和內存管理都很簡單,缺點是克隆需要分配新的內存和復制操作都會導致額外的開銷。 上面粗體部分表示,利用`C.CString`把go字符串轉化為C字符串,內存由C語言的`malloc`分配,不使用時需要`free`釋放內存,否則會出現內存泄漏。 ## 通過直接訪問C語言的內存來進行數據轉換 在`reflect`包中有字符串和切片的定義:在`reflect`包中有字符串和切片的定義: ```go type StringHeader struct { Data uintptr Len int } type SliceHeader struct { Data uintptr Len int Cap int } ``` 如果不希望單獨分配內存,可以在Go語言中直接訪問C語言的內存空間: ```go /* #include <string.h> char arr[10]; char *s = "Hello"; */ import "C" import ( "reflect" "unsafe" ) func main() { // 通過 reflect.SliceHeader 轉換 var arr0 []byte var arr0Hdr = (*reflect.SliceHeader)(unsafe.Pointer(&arr0)) arr0Hdr.Data = uintptr(unsafe.Pointer(&C.arr[0])) arr0Hdr.Len = 10 arr0Hdr.Cap = 10 // 通過切片語法轉換 arr1 := (*[31]byte)(unsafe.Pointer(&C.arr[0]))[:10:10] var s0 string var s0Hdr = (*reflect.StringHeader)(unsafe.Pointer(&s0)) s0Hdr.Data = uintptr(unsafe.Pointer(C.s)) s0Hdr.Len = int(C.strlen(C.s)) sLen := int(C.strlen(C.s)) s1 := string((*[31]byte)(unsafe.Pointer(C.s))[:sLen:sLen]) } ``` 因為**Go語言的字符串是只讀**的,用戶需要自己保證Go字符串在使用期間,底層對應的C字符串內容不會發生變化、內存不會被提前釋放掉。 在CGO中,會為字符串和切片生成和上面結構對應的C語言版本的結構體: ```go typedef struct { const char *p; GoInt n; } GoString; typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; ``` ## 在Go語言中直接訪問C語言的內存空間的例子 ```go package main /* #include <stdio.h> #include <stdlib.h> typedef struct { char *name; int age; }person; //一個長度為10的person結構體數組 person pon[10]; void NewPersonArray() { int n = 10; //初始化name for(int i = 0; i<n;i++){ pon[i].name = (char*)malloc(sizeof(char)*10); pon[i].age = i; sprintf(pon[i].name, "name:%d", i); } } //釋放內存 void freePersonArray() { for (int i = 0; i < 10; i ++){ free(pon[i].name); } } */ import "C" import ( "fmt" "unsafe" ) func main() { C.NewPersonArray() //通過切片語法轉換 arr1 := (*[20]C.person)(unsafe.Pointer(&C.pon[0]))[:10:10] for _, v := range arr1 { fmt.Printf("p.name: %s, p.age: %d\n", C.GoString(v.name), int(v.age) ) } C.freePersonArray() } ``` 通過切片語法轉換把C的結構體數組轉換為go的數據 ```go arr1 := (*[20]C.person)(unsafe.Pointer(&C.pon[0]))[:10:10] ``` >注意,如果`C.pon`是一個數組指針該方法就不適用,在go中無法使用索引`C.pon[0]`的 方法來訪問C數組指針中的數據。比如有一個長度為10的數組指針 *C.pon,則在go中無法通過C.pon[0] 索引的方式來訪問數據。如果有一個長度為10的數組`[10]C.pon`, 則可以使用C.pon[0] 索引的方式來訪問數據,不過在go中還需要轉化為切片才能訪問 輸出: ```shell p.name: name:0, p.age: 0 p.name: name:1, p.age: 1 p.name: name:2, p.age: 2 p.name: name:3, p.age: 3 p.name: name:4, p.age: 4 p.name: name:5, p.age: 5 p.name: name:6, p.age: 6 p.name: name:7, p.age: 7 p.name: name:8, p.age: 8 p.name: name:9, p.age: 9 ``` ## 給一個小彩蛋 在go中一個長度為10的char, 通過訪問數組首位元素的地址來輸出整個數組 ``` package main /* #include <stdio.h> void NewChar(char *s, int n) { sprintf(s, "I'm char"); } */ import "C" import ( "fmt" "unsafe" ) func main() { var c [10]C.char C.NewChar(&c[0], C.int(10)) //通過數組首元素地址輸出整個數組 arr := C.GoString((*C.char)(unsafe.Pointer(&c[0]))) fmt.Printf("111111: %s\n",arr) } ``` 參考文章:https://chai2010.cn/advanced-go-programming-book/ch2-cgo/ch2-03-cgo-types.html
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看