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