當前位置:網站首頁>C語言和go語言之間的交互 - C語言中使用go語言,使用的go語言又使用了c語言

C語言和go語言之間的交互 - C語言中使用go語言,使用的go語言又使用了c語言

2022-05-13 14:37:40wangwei830

一、go語言中使用C語言

go代碼中使用C代碼,在go語言的函數塊中,以注釋的方式寫入C代碼,然後緊跟import “C” 即可在go代碼中使用C函數

NewImage

代碼示例:

go代碼:testC.go

1 package main`` ``2`` ``3 ``/*`` ``4 #include `` ``5 #include `` ``6 void c_print(char *str) {`` ``7   printf("%s\n", str);`` ``8 }`` ``9 */``10 import ``"C"`  `//import “C” 必須單起一行,並且緊跟在注釋行之後``11 import ``"unsafe"``12``13 func main() {``14   s := ``"Hello Cgo"``15   cs := C.CString(s)``//字符串映射``16   C.c_print(cs)``//調用C函數``17   defer C.``free``(unsafe.Pointer(cs))``//釋放內存``18 }

運行結果:

$ go run testC.go
Hello Cgo

講解:

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、17行 利用defer C.free 和unsafe.Pointer顯示釋放調用C.Cstring所生成的內存塊

二、C語言中使用go語言

NewImage

代碼示例:

go代碼:print.go

1 package main`` ``2`` ``3 import ``"C"`` ``4 import ``"fmt"`` ``5`` ``6 ``//export go_print`` ``7 func go_print(value string) {`` ``8   fmt.Println(value)`` ``9 }``10``11 func main() {``//main函數是必須的 有main函數才能讓cgo編譯器去把包編譯成C的庫``12 }

講解:

1、第11行 這裏go代碼中的main函數是必須的,有main函數才能讓cgo編譯器去把包編譯成c的庫

2、第3行 import “C”是必須的,如果沒有import “C” 將只會build出一個.a文件,而缺少.h文件

3、第6行 //exoort go_print 這裏的go_print要和下面的的go函數名一致,並且下面一行即為要導出的go函數

4、命令執行完畢後會生成兩個文件 nautilus.a nautilus.h

nautilus.h中定義了go語言中的類型在C中對應的類型 和導出的go函數的函數聲明

如:

typedef signed char GoInt8;//對應go代碼中的int8類型

typedef struct { const char *p; GoInt n; } GoString;//對應go中的字符串

extern void go_print(GoString p0);//go中導出的函數的函數聲明

C代碼: c_go.c

1 #include “nautilus.h”``//引入go代碼導出的生成的C頭文件`` ``2 #include `` ``3`` ``4 ``int` `main() {`` ``5  ``char` `cvalue[] = ``"Hello This is a C Application"``;`` ``6  ``int` `length = ``strlen``(cvalue);`` ``7  GoString value = {cvalue, length};``//go中的字符串類型在c中為GoString`` ``8  go_print(value);`` ``9  ``return` `0;``10 }

編譯步驟

// as c-shared library
$ go build -buildmode=c-shared -o nautilus.a print.go

或者

// as c-archive
$ go build -buildmode=c-archive -o nautilus.a print.go

$ gcc -o c_go c_go.c nautilus.a

運行結果

$ ./c_go
Hello This is a C Application

講解:

1、第1行 #include “nautilus.h"包含go代碼導出生成的C頭文件

2、第7行 go中字符串類型在c中為GoString 定義為typedef struct { const char *p; GoInt n; } GoString; p為字符串指針,n為長度;所以這裏通過GoString value = {cavalue, length}將C中的char賦值給GoString

3、第8行 go_print調用對應函數

三、C語言中使用go語言,使用的go語言又使用了c語言

NewImage

代碼示例:

被go調用的C代碼 hello.h

1 #ifndef HELLO_H`` ``2 #define HELLO_H`` ``3`` ``4`` ``5 #include `` ``6 #include 7`` ``8 ``void` `go_print_c(``char` `*str);`` ``9``10 #endif

被go調用的C代碼 hello.c

1 #include ``"hello.h"`` ``2`` ``3 ``void` `go_print_c(``char` `*str) {`` ``4   ``printf``(``"%s\n"``, str);`` ``5 }

被C調用的go代碼 print.go

1 package main`` ``2`` ``3 ``//#include "hello.h"`` ``4 import ``"C"`` ``5`` ``6 ``//export go_print`` ``7 func go_print(value string) {`` ``8   cs := C.CString(value)`` ``9   C.go_print_c(cs)``10 }``11``12 func main() {``13 }

講解:

1、這裏在函數前面加上了inline關鍵字

如果把C代碼放入go代碼注釋塊中並且沒有inline關鍵字中,會出現重定義的錯誤

p.go

1 package main`` ``2`` ``3 ``/*`` ``4 #include `` ``5 #include `` ``6 void go_print_c(char *str) {`` ``7   printf("%s\n", str);`` ``8 }`` ``9 */``10 import ``"C"``11 import ``"unsafe"``12``13 ``//export go_print``14 func go_print(value string) {``15   cs := C.CString(value)``16   C.go_print_c(cs)``17 }``18 ... 

go build -buildmode=c-shared -o nautilus.a print.go執行失敗

duplicate symbol go_print_c in:
$WORK/
/Users/baidu/go_code/t/_obj/cgo_export.o
$WORK/
/Users/baidu/go_code/t/_obj/p.cgo2.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决辦法是給函數加上inline或者static關鍵字將函數改成內部鏈接,或者是像上面那樣include頭文件

C代碼 _c_go.c

1 #include ``"nautilus.h"`` ``2 #include3`` ``4 ``int` `main() {`` ``5  ``printf``(``"This is a C Application.\n"``);`` ``6  ``char` `cvalue[] = ``"hello world"``;`` ``7  ``int` `length = ``strlen``(cvalue);`` ``8  GoString value = {cvalue, length};`` ``9  go_print(value);``10  ``return` `0;``11 }

編譯步驟:

// as c-shared library
$ go build -buildmode=c-shared -o nautilus.a

或者

// as c-archive
$ go build -buildmode=c-archive -o nautilus.a

$ gcc -o c_go_c c_go.c nautilus.a

運行結果

$ ./c_go_c.o
This is a C Application.
hello world

四、參考文獻

http://www.cnblogs.com/sevenyuan/p/4544294.html Go與C語言的互操作

http://blog.ralch.com/tutorial/golang-sharing-libraries/ Sharing Golang packages to C and Go

https://groups.google.com/forum/#!topic/golang-china/vUd4Civs_Bs google go論壇

http://blog.csdn.net/u014633283/article/details/52225274 GO中調用C代碼(CGO)中的坑

作者:magicsoar

出處:http://www.cnblogs.com/magicsoar/

聯系方式:[email protected]郵我郵我

qq:1021842556點我

版權聲明
本文為[wangwei830]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/133/202205131423020420.html

隨機推薦