<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] ## 使用自己的C函數 文件名:testC.go ``` package main /* #include <stdio.h> #include <stdlib.h> void c_print(char *str) { printf("%s\n", str); } */ import "C" //import “C” 必須單起一行,并且緊跟在注釋行之后 import "unsafe" func main() { s := "Hello Cgo" cs := C.CString(s) //字符串映射 C.c_print(cs) //調用C函數 defer C.free(unsafe.Pointer(cs)) //釋放內存 } ``` 說明: 1、go代碼中的C代碼,需要用注釋包裹,塊注釋和行注釋均可,其次import “C”是必須的,并且和上面的C代碼之間不能用空行分割,必須緊密相連 如果執行go run \*\*時出現 ``` # command-line-arguments could not determine kind of name for xxx ``` 那么就需要考慮 是不是improt “C”和上面的C代碼沒有緊挨著導致了 2、import “C” 并沒有導入一個名為C的包,這里的import “C”類似于告訴Cgo將之前注釋塊中的C代碼生成一段具有包裝性質的Go代碼 3、訪問C語言中的函數需要在前面加上C.前綴,如C.Cstring C.go\_print C.free 4、對于C語中的原生類型,Cgo都有對應的Go語言中的類型 如go代碼中C.int,C.char對應于c語言中的int,signed char,而C語言中void\*指針在Go語言中用特殊的unsafe.Pointer(cs)來對應 而Go語言中的string類型,在C語言中用字符數組來表示,二者的轉換需要通過go提供的一系列函數來完成: * C.Cstring : 轉換go的字符串為C字符串,C中的字符串是使用malloc分配的,所以需要調用C.free來釋放內存 * C.Gostring : 轉換C字符串為go字符串 * C.GoStringN : 轉換一定長度的C字符串為go字符串 需要注意的是每次轉換都會導致一次內存復制,所以字符串的內容是不可以修改的 5、**利用defer C.free 和unsafe.Pointer顯示釋放調用C.Cstring所生成的內存塊** 然后我們編譯以下測試看看。 ``` go run testC.go ``` ## C.CString的解釋 在[cgo-1](https://golang.org/cmd/cgo/)中關于 C.CString 的注釋里面已經寫的很清楚了。 需要手動釋放,C.CString 返回的指針。 ``` // Go string to C string // The C string is allocated in the C heap using malloc. // It is the caller's responsibility to arrange for it to be // freed, such as by calling C.free (be sure to include stdlib.h // if C.free is needed). func C.CString(string) *C.char ``` 在[cgo-2](http://blog.golang.org/c-go-cgo)中有釋放 C.CString 返回指針的示例: ``` func Print(s string) { cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) C.fputs(cs, (*C.FILE)(C.stdout)) } ``` 這個問題我想后來也是引起了Go語言作者的注意了, 在go1.7新版本發布信息中我發現新出了一個 C.Bytes 的類型,C.Bytes 就不需要像 C.CString 一樣需要手動釋放內存了。 ## 用Go重新實現C函數 定義一個頭文件 ``` //hello.h void SayHello(const char* c); ``` 定義hello.go文件 SayHello 實現 ``` //hello.go package main import "C" import "fmt" //export SayHello func SayHello(s *C.char) { fmt.Println(C.GoString(s)) } ``` 我們通過CGO的`//export SayHello`指令將Go語言實現的函數`SayHello`導出為C語言函數。為了適配CGO導出的C語言函數,我們禁止了在函數的聲明語句中的const修飾符。需要注意的是,這里其實有兩個版本的`SayHello`函數:一個Go語言環境的;另一個是C語言環境的。cgo生成的C語言版本SayHello函數最終會通過橋接代碼調用Go語言版本的SayHello函數。 通過面向C語言接口的編程技術,我們不僅僅解放了函數的實現者,同時也簡化的函數的使用者。現在我們可以將SayHello當作一個標準庫的函數使用(和puts函數的使用方式類似): ``` //say_hello.go package main //#include <hello.h> import "C" func main() { C.SayHello(C.CString("Hello, World\n")) } ``` ## 面向C接口的Go編程 嘗試將例子中的幾個文件重新合并到一個Go文件。下面是合并后的成果: ``` //c_say_hello.go package main import ( "fmt" "runtime" "strconv" "strings" ) /* void SayHello(char* c); */ import "C" //獲取 gorutine id func GetGoid() int64 { var ( buf [64]byte n = runtime.Stack(buf[:], false) stk = strings.TrimPrefix(string(buf[:n]), "goroutine ") ) idField := strings.Fields(stk)[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Errorf("can not get goroutine id: %v", err)) } return int64(id) } func main() { fmt.Println("1111111=", GetGoid()) C.SayHello(C.CString("hello world!\n")) } //export SayHello func SayHello(s *C.char) { fmt.Println("2222222222=", GetGoid()) fmt.Println(C.GoString(s)) } ``` 現在版本的CGO代碼中C語言代碼的比例已經很少了,但是我們依然可以進一步以Go語言的思維來提煉我們的CGO代碼。通過分析可以發現`SayHello`函數的參數如果可以直接使用Go字符串是最直接的。在Go1.10中CGO新增加了一個`_GoString_`預定義的C語言類型,用來表示Go語言字符串。下面是改進后的代碼: ``` //test_hello.go package main import ( "fmt" "runtime" "strconv" "strings" ) /* void SayHello(_GoString_ c); // 修改1 */ import "C" //獲取 gorutine id func GetGoid() int64 { var ( buf [64]byte n = runtime.Stack(buf[:], false) stk = strings.TrimPrefix(string(buf[:n]), "goroutine ") ) idField := strings.Fields(stk)[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Errorf("can not get goroutine id: %v", err)) } return int64(id) } func main() { fmt.Println("1111111=", GetGoid()) C.SayHello("hello world!\n") // 修改1 } //export SayHello func SayHello(s string) { fmt.Println("2222222222=", GetGoid()) fmt.Println(s) // 修改1 } ``` *思考題: main函數和SayHello函數是否在同一個Goroutine里執行?* ``` $ go run test_hello.go 1111111= 1 2222222222= 1 hello world! ``` 可以看到main函數和SayHello函數在統一個Goroutine里執行
                  <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>

                              哎呀哎呀视频在线观看