Go 语言交互性
? ?作為直接繼承于C的語(yǔ)言,Go提供了與C語(yǔ)言交互的功能,稱為Cgo。先來(lái)看看一個(gè)例子:
? ?直接運(yùn)行 go run命令即可.
? ?事實(shí)上,根本就不存在一個(gè)名為C的包。這個(gè)import語(yǔ)句其實(shí)就是一個(gè)信號(hào),告訴Cgo它應(yīng)該開始工作了。做什么事情呢?就是對(duì)應(yīng)這條import語(yǔ)句之前的塊注釋中的C源代碼自動(dòng)生成包裝性質(zhì)的Go代碼。
? ?這時(shí)候我們?cè)撟⒁獾絠mport語(yǔ)句前緊跟的注釋了。這個(gè)注釋的內(nèi)容是有意義的,而不是傳統(tǒng)意義上的注釋作用。這個(gè)例子里用的是一個(gè)塊注釋,實(shí)際上用行注釋也是沒(méi)問(wèn)題的,只要是緊貼在import語(yǔ)句之前即可。比如下面也是正確的Cgo寫法:
1.類型映射
? ?在跨語(yǔ)言交互中,比較復(fù)雜的問(wèn)題有兩個(gè):類型映射以及跨越調(diào)用邊界傳遞指針?biāo)鶐?lái)的對(duì)象生命周期和內(nèi)存管理的問(wèn)題。對(duì)于C語(yǔ)言的原生類型,Cgo都會(huì)將其映射為Go語(yǔ)言中的類型:
? ·C.char和C.schar===>signed char
? ·C.uchar===========>unsigned char
? ·C.short和C.ushort=>unsigned short
? ·C.int和C.uint=====>unsigned int
? ·C.long和C.ulong===>unsigned long
? ·C.longlong========>long long
? ·C.ulonglong=======>unsigned long long
? ·C.float和C.double=>float double
? ? C語(yǔ)言中的viod*指針類型在Go語(yǔ)言中則用特殊的unsafe.Pointer類型來(lái)對(duì)應(yīng)。
? ? C語(yǔ)言中的struct、 union和enum類型,對(duì)應(yīng)到Go語(yǔ)言中都會(huì)變成帶這樣前綴的類型名稱:struct_、 union_和enum_。比如一個(gè) 在C語(yǔ)言中叫做person的struct會(huì)被Cgo翻譯為C.struct_person。
? ?如果C語(yǔ)言中的類型名稱或變量名稱與Go語(yǔ)言的關(guān)鍵字相同, Cgo會(huì)自動(dòng)給這些名字加上下劃線前綴。
?
2.字符串映射
? ?Cgo提供了一系列函數(shù)來(lái)提供支持:C.CString、C.GoString和C.GoStringN。需要注意的是,每次轉(zhuǎn)換都將導(dǎo)致一次內(nèi)存復(fù)制,因此字符串內(nèi)容其實(shí)是不可以修改的(實(shí)際上,Go語(yǔ)言的string也不允許對(duì)其中的內(nèi)容進(jìn)行修改)。
? ?由于C.CString的內(nèi)存管理方式與Go語(yǔ)言自身的內(nèi)存管理方式不兼容,我們?cè)O(shè)法期待Go語(yǔ)言可以幫助我們做垃圾收集,因此在使用完成后必須顯示釋放調(diào)用C.CString所生成的內(nèi)存塊,否則將導(dǎo)致嚴(yán)重的內(nèi)存泄漏。結(jié)合我們之前學(xué)過(guò)的defer用法,所有用到C.CString的代碼大致都可以寫成如下的風(fēng)格:
3.C程序
? ?在import "C"之前的注釋塊中,可以寫任意合法的C源代碼,而Cgo都會(huì)進(jìn)行相應(yīng)的處理并生成對(duì)應(yīng)的Go代碼。如下:
? ?這個(gè)塊注釋里就直接寫了個(gè)C函數(shù),它使用C標(biāo)準(zhǔn)庫(kù)里的printf()打印了一句話。
? ?還有另外一個(gè)問(wèn)題,那就是如果這里的C代碼需要依賴一個(gè)非C標(biāo)準(zhǔn)庫(kù)的第三方庫(kù),怎么辦呢?如果不解決的話必然會(huì)有鏈接時(shí)錯(cuò)誤。Cgo提供了#cgo這樣的偽C文法,讓開發(fā)者有機(jī)會(huì)指定依賴的第三方庫(kù)和編譯選項(xiàng)。
? ?下面的例子示范了#cgo的第一種用法:
? ? 這個(gè)例子示范了如何使用CFLAGS來(lái)傳入編譯選項(xiàng),使用LDFLAGS來(lái)傳入鏈接選項(xiàng)。 #cgo還有另外一種更簡(jiǎn)便一些的用法,如下所示:
?
4.函數(shù)調(diào)用
? ? 對(duì)于常規(guī)的函數(shù)調(diào)用,開發(fā)者只要在運(yùn)行cgo指令后查看一下生成的Go代碼,就可以知道如何寫對(duì)應(yīng)的調(diào)用代碼。對(duì)于常規(guī)返回了一個(gè)值的函數(shù),調(diào)用者可以用以下的方式順便得到錯(cuò)誤碼:
? ?在傳遞數(shù)組類型的參數(shù)時(shí)需要注意,在Go語(yǔ)言中將第一個(gè)元素的地址作為整個(gè)數(shù)組的起始地址傳入,這一點(diǎn)就不如C語(yǔ)言本身直接傳入數(shù)組名字那么方便了。下面為一個(gè)傳遞數(shù)組的例子:
?
5.編譯Cgo
? ?編譯Cgo代碼非常容易,我們不需要做任何特殊的處理。 Go安裝后,會(huì)自帶一個(gè)cgo命令行工具,它用于處理所有帶有Cgo代碼的Go文件,生成Go語(yǔ)言版本的調(diào)用封裝代碼。而Go工具集對(duì)cgo命令行工具再次進(jìn)行了良好的封裝,使構(gòu)建過(guò)程能夠自動(dòng)識(shí)別和處理帶有Cgo代碼的Go源代碼文件,完全不給用戶增加額外的工作負(fù)擔(dān)。
?
參考:
https://www.yuque.com/docs/share/e71f5d60-67f5-46af-b4da-f79808bb995c
總結(jié)
- 上一篇: 刷机-升级到3.90M33-3的方法
- 下一篇: 在PSP上玩《大旋风 Twin Hawk