Aus beruflichen Gründen ist es in letzter Zeit notwendig, gegenseitige Aufrufe zwischen Go-Sprache und C-Sprache zu implementieren. Da die Go-Sprache und die C-Sprache untrennbar miteinander verbunden sind, können die Aufrufe zwischen den beiden über die Sprachebene realisiert werden. Nachfolgend finden Sie eine Zusammenfassung davon.
Go-Sprache ruft C-Sprache auf
Das Folgende ist ein kurzes Beispiel:
package main // #include <stdio.h> // #include <stdlib.h> /* void print(char *str) { printf("%s\n", str); } */ import "C" import "unsafe" func main() { s := "Hello Cgo" cs := C.CString(s) C.print(cs) C.free(unsafe.pointer(cs)) }
Im Vergleich zum „normalen“ Go-Code weist der obige Code mehrere „besondere“ Dinge auf:
erscheint in den Kommentaren am Anfang Das Include Wort in der C-Sprach-Header-Datei
definiert die C-Sprachfunktion print im Kommentar
importiert ein „Paket“ mit dem Namen C
ruft die oben in der Hauptfunktion definierte C-Sprachfunktion print auf
Erstens muss der C-Sprachcode in der Go-Quelldatei mit Kommentaren umschlossen werden, genau wie die obige Include-Header-Datei und die Druckfunktionsdefinition. Zweitens ist die Import-Anweisung „C“ erforderlich, die mit The zusammenhängt Die oben genannten C-Codes dürfen nicht durch Leerzeilen getrennt werden und müssen eng miteinander verbunden sein. Das „C“ ist hier kein Paketname, sondern ein Konzept ähnlich einem Namespace, oder es kann als Pseudopaket verstanden werden. Alle Syntaxelemente der C-Sprache befinden sich schließlich unter diesem Pseudopaket c-Syntaxelemente, sie müssen im obigen Code Pseudopaketpräfixe wie C.uint und C.print, C.free usw. hinzufügen.
Für eine detailliertere Verwendung des Aufrufs der C-Sprache in Go lesen Sie bitte die Interoperabilität zwischen Go und C-Sprache. In diesem Artikel wird nicht einzeln darauf eingegangen.
Im obigen Beispiel ist die C-Sprache in den Go-Code eingebettet. Wenn der Code größer und komplexer ist, ist dies offensichtlich sehr unprofessionell. Kann der C-Sprachcode also vom Go-Code getrennt und separat definiert werden? Die Antwort lautet: Ja, dies kann über gemeinsam genutzte Bibliotheken erreicht werden.
cgo stellt die Anweisung #cgo
bereit, um anzugeben, mit welchen gemeinsam genutzten Bibliotheken der Go-Quellcode nach der Kompilierung verknüpft wird. Das Beispiel sieht wie folgt aus: #cgo
指示符可以指定go源码在编译后与哪些共享库进行链接。例子如下:
// hello.go package main // #cgo LDFLAGS: -L ./ -lhello // #include <stdio.h> // #include <stdlib.h> // #include "hello.h" import "C" func main() { C.hello() } // hello.c #include "hello.h" void hello() { printf("hello, go\n"); } // hello.h extern void hello();
其中在hello.go中,#cgo
指示符后面添加LDFLAGS: -L ./ -lhello
,作用是在go代码编译时,指定在当前目录查找so库并进行链接。
因此,只需要把hello.c编译成动态库,再编译go代码,即可在运行go代码的时候调用共享库中的c语言函数。指令如下:
gcc -fPIC -o libhello.so hello.c
go build -o hello
./hello
c语言调用go语言
与在go中调用c源码相比,在c中使用go函数的场合较少。因为一般来说,采用高级语言作为粘合剂调用低级语言能充分发挥各自的特点,而用低级语言调用高级语言反而有可能降低低级语言的性能优势,在go中,可以使用”export + 函数名“来导出go函数为c代码所用,看一个简单的例子:
// hello.go package main import "C" import "fmt" // export Go2C func Go2C() { fmt.Println("hello, C") }
可通过go build
的编译选项,将go代码编译成共享库以供c代码调用。注意,编译so库时必须存在main及main函数(即使main函数为空)。编译指令如下:go build -v -x -buildmode=c-shared -o libhello.so hello.go
。
编译成功后,只需在c代码中引入新生成的头文件及编译时链接动态库即可实现go函数的调用。代码如下:
// hello.c #include <stdio.h> #include "libhello.h" int main() { Go2C(); return 0; }
通过gcc -o hello -L. -lhello
,即可编译成可执行程序。注意,运行前必须确定共享库运行时查找路径中存在需要链接的共享库,可通过将so库路径放到/usr/lib或者修改环境变量LD_LIBRARY_PATH。
小结
go语言可以通过内嵌c代码的形式调用c语言,也可以通过调用共享库函数的方式实现;至于c语言调用go函数,则可以通过go build
rrreee
LDFLAGS: -L ./ -lhello
nach dem Indikator #cgo
hinzu, der beim Kompilieren von Go-Code verwendet wird . Gibt an, nach der so-Bibliothek im aktuellen Verzeichnis zu suchen und sie zu verknüpfen.