新聞中心
大家好,我是煎魚。

成都創(chuàng)新互聯(lián)主打移動網(wǎng)站、成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)站改版、網(wǎng)絡(luò)推廣、網(wǎng)站維護(hù)、主機域名、等互聯(lián)網(wǎng)信息服務(wù),為各行業(yè)提供服務(wù)。在技術(shù)實力的保障下,我們?yōu)榭蛻舫兄Z穩(wěn)定,放心的服務(wù),根據(jù)網(wǎng)站的內(nèi)容與功能再決定采用什么樣的設(shè)計。最后,要實現(xiàn)符合網(wǎng)站需求的內(nèi)容、功能與設(shè)計,我們還會規(guī)劃穩(wěn)定安全的技術(shù)方案做保障。
最近因為各種奇怪的原因,接觸到了 Go 特色之一 CGO。這方面的相關(guān)內(nèi)容也相對少一些,給大家拋磚引玉。
圖片來源于 marlin
畢竟很多跨語言調(diào)用,還是會依賴 CGO 這個特性。希望大家在真正要用時有個前置知識墊肚子。
CGO 是什么
CGO 就是 C 和 Go,兩個編程語言。指的是能夠創(chuàng)建調(diào)用 C 代碼的 Go 包。對照著 Go 代碼中的 “C”:
package main
import "C"
func main() {}一旦程序中出現(xiàn) import "C",則意味著開啟 CGO 特性。在進(jìn)行 go build 等階段時,將會調(diào)用 C 編譯器(通常是 gcc 或 clang)。
CGO 對應(yīng)的環(huán)境變量是 CGO_ENABLED,設(shè)置為 1 則開啟 CGO,為 0 則關(guān)閉 CGO。
編譯命令如下:
CGO_ENABLED=0 go build -o hellojy main.go當(dāng)然,對于默認(rèn)值。該環(huán)境變量值為 1,C 編譯器也是使用 gcc。我們可以通過 go env 看到:
一旦關(guān)閉就會影響 CGO 編譯。需要特別留意,交叉編譯時會默認(rèn)關(guān)閉 CGO。
CGO 快速上手
最小 Demo
先來一個 CGO 的 Go 例子:
package main
//#include
import "C"
func main() {
s := C.CString("hello world.")
C.puts(s)
} 運行 go run main.go,輸出結(jié)果:
hello world.聲明 C 注解
如果你沒有了解過 CGO,看到上面的例子,可能會有好幾個疑問。
首先是 include:
//#include
import "C" import "C" 我們懂,是導(dǎo)入 C 的偽包。前面的注解是什么?
無論是:
//#include 又或是:
/*
#include
#include
*/ 實際上這是導(dǎo)入 C 前的注解,注解內(nèi)容可以包含任何 C 代碼,例如:函數(shù)、變量的聲明定義、庫引用等。(該注解要緊挨導(dǎo)入語句)
回到 Demo 本身,如果我們?nèi)サ?nbsp;//#include
# command-line-arguments
./main.go:7:2: could not determine kind of name for C.puts去掉后,語句 C.puts(s) 將無法運行。
實際上 stdio.h 的全稱是:standard input output.header(標(biāo)準(zhǔn)輸入輸出頭文件)。該文件大都是些輸入輸出函數(shù)的聲明,引用了這庫,就能使用 C 的 puts 方法。
其他同理,你在注解中聲明、定義的東西,均可以在 Go 代碼中通過 C 這個偽包來引用和調(diào)用。
其次像是 CString 方法,屬于在 Go 和 C 類型之間需要復(fù)制數(shù)據(jù)的特殊函數(shù),偽包 C 有進(jìn)行預(yù)定義。
例如:
func C.CString(string) *C.char
func C.CBytes([]byte) unsafe.Pointer
func C.GoString(*C.char) string
func C.GoStringN(*C.char, C.int) string
func C.GoBytes(unsafe.Pointer, C.int) []byteGo 和 C 類型對照
Go 官方有提供一份基礎(chǔ)類型的對照表,大家可以參照來使用和理解。
如下:
|
C 語言類型 |
CGO 類型 |
Go語言類型 |
|
char |
C.char |
byte |
|
singed char |
C.schar |
int8 |
|
unsigned char |
C.uchar |
uint8 |
|
short |
C.short |
int16 |
|
unsigned short |
C.ushort |
uint16 |
|
int |
C.int |
int32 |
|
unsigned int |
C.uint |
uint32 |
|
long |
C.long |
int32 |
|
unsigned long |
C.ulong |
uint32 |
|
long long int |
C.longlong |
int64 |
|
unsigned long long int |
C.ulonglong |
uint64 |
|
float |
C.float |
float32 |
|
double |
C.double |
float64 |
|
size_t |
C.size_t |
uint |
注意事項
使用 CGO,除了會帶來一定的性能損耗外。需要特別注意的是:內(nèi)存泄露。因為 Go 是帶垃圾回收機制的編程語言,而使用了 C 后,需要手動的管理內(nèi)存。
還是這個 Demo:
package main
//#include
import "C"
func main() {
s := C.CString("hello world.")
C.puts(s)
} 如果這是一個常駐進(jìn)程,也沒有任何釋放動作。用 C.CString 方法所申請的變量 s 就會泄露。
因此與 “C” 相關(guān)的變量創(chuàng)建,需要進(jìn)行手動的內(nèi)存管理。正確的代碼如下:
/*
#include
#include
*/
import "C"
import (
"unsafe"
)
func main() {
b := C.CString("hello world.")
C.puts(b)
C.free(unsafe.Pointer(b))
} 需要調(diào)用 C.free 方法進(jìn)行主動的內(nèi)存釋放。如果該程序自然結(jié)束,也會自動回收。
總結(jié)
在今天這篇文章中,我們介紹了 Go 語言中 CGO 的基礎(chǔ)知識和快速入門。整體上,只要適應(yīng)了寫法,CGO 的用法就不算太麻煩。
需要特別注意手動內(nèi)存管理、性能損耗等多方面的制約。后續(xù)我們也會繼續(xù)深入 CGO 方面的內(nèi)容。
網(wǎng)站名稱:快速上手GoCGO,掌握在Go里寫C!
新聞來源:http://m.fisionsoft.com.cn/article/cojopso.html


咨詢
建站咨詢
