<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] 轉載:https://studygolang.com/articles/2909 ## 概述 在Go語言中,Slice本質是什么呢?是一個reflect.SliceHeader結構體和這個結構體中Data字段所指向的內存。String本質是什么呢?是一個reflect.StringHeader結構體和這個結構體所指向的內存。 在Go語言中,指針的本質是什么呢?是unsafe.Pointer和uintptr。 當你清楚了它們的本質之后,你就可以隨意的玩弄它們,嘿嘿嘿。 ## 獲得 Slice 和 String 的內存數據 有一個 CGO 接口要調用,需要你把一個字符串數據或者字節數組數據從Go這邊傳遞到C那邊. 查了各種教程和文檔,它們都告訴你要用 C.GoString 或 C.GoBytes 來轉換數據。 但是,當你調用這兩個函數的時候,發生了什么事情呢?這時候Go復制了一份數據,然后再把新數據的地址傳給C,因為Go不想冒任何風險。 **你的C程序只是想一次性的用一下這些數據,也不得不做一次數據復制,這對于一個性能癖來說是多麼可怕的一個事實**! 這時候我們就需要一個黑魔法,來做到不拷貝數據又能把指針地址傳遞給C。 ``` // returns &s[0], which is not allowed in go func stringPointer(s string) unsafe.Pointer { p := (*reflect.StringHeader)(unsafe.Pointer(&s)) return unsafe.Pointer(p.Data) } // returns &b[0], which is not allowed in go func bytePointer(b []byte) unsafe.Pointer { p := (*reflect.SliceHeader)(unsafe.Pointer(&b)) return unsafe.Pointer(p.Data) } ``` 以上就是黑魔法第一式,我們先去到Go字符串的指針,它本質上是一個 *reflect.StringHeader ,但是Go告訴我們這是一個 *string ,我們告訴Go它同時也是一個 unsafe.Pointer ,Go說好吧它是,于是你得到了unsafe.Pointer,接著你就躲過了Go的監視,偷偷的把unsafe.Pointer轉成了 *reflect.StringHeader 。 有了 *reflect.StringHeader ,你很快就取到了Data字段指向的內存地址,它就是Go保護著不想給你看到的隱秘所在,你把這個地址偷偷告訴給了C,于是C就愉快的偷看了Go的隱私。 ## 把string轉化為 *C.char ``` package main /* #include <stdio.h> int test1(const char* s) { puts(s); } */ import "C" import ( "reflect" "unsafe" ) func stringPointer(s string)unsafe.Pointer { p := (*reflect.StringHeader)(unsafe.Pointer(&s)) return unsafe.Pointer(p.Data) } func GetCString(s string)*C.char { v := s + "\000" p := stringPointer(v) return (*C.char)(p) } func main() { s := "ahello" C.test1(GetCString(s)) } ``` 思考為什么 v := s + "\000" 字符串后面要加 "\000".我嘗試了,如果不加轉換會報錯.如果加上 "\\\0" 則字符串打印出來結尾會多一個 \0 可以自己嘗試一下 ## 把 []byte 轉成 string 普通的轉換方法是 ``` b := []byte("hello world") c := string(b) // []byte => string d := []byte(c) // string =>> []byte ``` 使用指針 unsafe.Pointe 來轉換 ``` package labs28 import "testing" import "unsafe" func Test_ByteString(t *testing.T) { var x = []byte("Hello World!") var y = *(*string)(unsafe.Pointer(&x)) var z = string(x) if y != z { t.Fail() } } func Benchmark_Normal(b *testing.B) { var x = []byte("Hello World!") for i := 0; i < b.N; i ++ { _ = string(x) } } func Benchmark_ByteString(b *testing.B) { var x = []byte("Hello World!") for i := 0; i < b.N; i ++ { _ = *(*string)(unsafe.Pointer(&x)) } } ```
                  <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>

                              哎呀哎呀视频在线观看