掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本文由go語(yǔ)言教程欄目給大家介紹golang與c語(yǔ)言是如何相互調(diào)用 ,希望對(duì)需要的朋友有所幫助!

成都創(chuàng)新互聯(lián)公司10多年成都企業(yè)網(wǎng)站建設(shè)服務(wù);為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì)及高端網(wǎng)站定制服務(wù),成都企業(yè)網(wǎng)站建設(shè)及推廣,對(duì)成都鑿毛機(jī)等多個(gè)領(lǐng)域擁有多年的網(wǎng)站推廣經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。
go語(yǔ)言與c語(yǔ)言的相互調(diào)用
最近由于工作原因,需要實(shí)現(xiàn)go語(yǔ)言與c語(yǔ)言的相互調(diào)用。由于go語(yǔ)言與c語(yǔ)言有著千絲萬(wàn)縷的曖昧關(guān)系,兩者之間的調(diào)用可以通過(guò)語(yǔ)言層面實(shí)現(xiàn)。下文是對(duì)此的總結(jié)。
以下為一個(gè)簡(jiǎn)短的例子:
package main // #include// #include /* 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)) }
與“正?!钡膅o代碼相比,上述代碼有幾處“特殊”的地方:
在開(kāi)頭的注釋中出現(xiàn)了c語(yǔ)言頭文件的include字樣
在注釋中定義了c語(yǔ)言函數(shù)print
import了一個(gè)名為C的“包”
在main函數(shù)中調(diào)用了上述定義的c語(yǔ)言函數(shù)print
首先,go源碼文件中的c語(yǔ)言代碼是需要用注釋包裹的,就像上面的include頭文件以及print函數(shù)定義;其次,import "C"這個(gè)語(yǔ)句是必須的,而且其與上面的c代碼之間不能用空行分隔,必須緊密相連。這里的”C“不是包名,而是一種類似名字空間的概念,或可以理解為偽包,c語(yǔ)言所有語(yǔ)法元素均在該偽包下面;最后,訪問(wèn)c語(yǔ)法元素時(shí)都要在其前面加上偽包前綴,比如C.uint和上面代碼中的C.print、C.free等。
更詳細(xì)的在go中調(diào)用c語(yǔ)言的用法可以參考Go與C語(yǔ)言的互操作,本文不再一一細(xì)述。
在上面的例子中,c語(yǔ)言是內(nèi)嵌在go代碼中的,如果代碼量更大更復(fù)雜的話,這顯然是很不”專業(yè)“的。那么,是否可以將c語(yǔ)言代碼從go代碼中分離出去,單獨(dú)定義呢?答案是肯定的,可以通過(guò)共享庫(kù)的方式實(shí)現(xiàn)。
cgo提供了#cgo指示符可以指定go源碼在編譯后與哪些共享庫(kù)進(jìn)行鏈接。例子如下:
// hello.go package main // #cgo LDFLAGS: -L ./ -lhello // #include// #include // #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代碼編譯時(shí),指定在當(dāng)前目錄查找so庫(kù)并進(jìn)行鏈接。
因此,只需要把hello.c編譯成動(dòng)態(tài)庫(kù),再編譯go代碼,即可在運(yùn)行g(shù)o代碼的時(shí)候調(diào)用共享庫(kù)中的c語(yǔ)言函數(shù)。指令如下:
gcc -fPIC -o libhello.so hello.c
go build -o hello
./hello
與在go中調(diào)用c源碼相比,在c中使用go函數(shù)的場(chǎng)合較少。因?yàn)橐话銇?lái)說(shuō),采用高級(jí)語(yǔ)言作為粘合劑調(diào)用低級(jí)語(yǔ)言能充分發(fā)揮各自的特點(diǎn),而用低級(jí)語(yǔ)言調(diào)用高級(jí)語(yǔ)言反而有可能降低低級(jí)語(yǔ)言的性能優(yōu)勢(shì),在go中,可以使用”export + 函數(shù)名“來(lái)導(dǎo)出go函數(shù)為c代碼所用,看一個(gè)簡(jiǎn)單的例子:
// hello.go
package main
import "C"
import "fmt"
// export Go2C
func Go2C() {
fmt.Println("hello, C")
}
可通過(guò)go build的編譯選項(xiàng),將go代碼編譯成共享庫(kù)以供c代碼調(diào)用。注意,編譯so庫(kù)時(shí)必須存在main及main函數(shù)(即使main函數(shù)為空)。編譯指令如下:go build -v -x -buildmode=c-shared -o libhello.so hello.go。
編譯成功后,只需在c代碼中引入新生成的頭文件及編譯時(shí)鏈接動(dòng)態(tài)庫(kù)即可實(shí)現(xiàn)go函數(shù)的調(diào)用。代碼如下:
// hello.c #include#include "libhello.h" int main() { Go2C(); return 0; }
通過(guò)gcc -o hello -L. -lhello,即可編譯成可執(zhí)行程序。注意,運(yùn)行前必須確定共享庫(kù)運(yùn)行時(shí)查找路徑中存在需要鏈接的共享庫(kù),可通過(guò)將so庫(kù)路徑放到/usr/lib或者修改環(huán)境變量LD_LIBRARY_PATH。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流