- 相關(guān)推薦
Go與C語(yǔ)言的操作
Go有強(qiáng)烈的C背景,除了語(yǔ)法具有繼承性外,其設(shè)計(jì)者以及其設(shè)計(jì)目標(biāo)都與C語(yǔ)言有著千絲萬(wàn)縷的聯(lián)系。在Go與C語(yǔ)言互操作(Interoperability)方面,Go更是提供了強(qiáng)大的支持。尤其是在Go中使用C,你甚至可以直接在Go源文件中編寫(xiě)C代碼,這是其他語(yǔ)言所無(wú)法望其項(xiàng)背的。下面是小編為大家?guī)?lái)的Go與C語(yǔ)言的操作的知識(shí),歡迎閱讀。
一、Go調(diào)用C代碼的原理
下面是一個(gè)短小的例子:
復(fù)制代碼
package main
// #include
// #include
/*
void print(char *str) {
printf("%s ", str);
}
*/
import "C"
import "unsafe"
func main() {
s := "Hello Cgo"
cs := C.CString(s)
C.print(cs)
C.free(unsafe.Pointer(cs))
}
復(fù)制代碼
與"正常"Go代碼相比,上述代碼有幾處"特殊"的地方:
1) 在開(kāi)頭的注釋中出現(xiàn)了C頭文件的include字樣
2) 在注釋中定義了C函數(shù)print
3) import的一個(gè)名為C的"包"
4) 在main函數(shù)中居然調(diào)用了上述的那個(gè)C函數(shù)-print
沒(méi)錯(cuò),這就是在Go源碼中調(diào)用C代碼的步驟,可以看出我們可直接在Go源碼文件中編寫(xiě)C代碼。
首先,Go源碼文件中的C代碼是需要用注釋包裹的,就像上面的include 頭文件以及print函數(shù)定義;
其次,import "C"這個(gè)語(yǔ)句是必須的,而且其與上面的C代碼之間不能用空行分隔,必須緊密相連。這里的"C"不是包名,而是一種類(lèi)似名字空間的概念,或可以理解為偽包,C語(yǔ)言所有語(yǔ)法元素均在該偽包下面;
最后,訪問(wèn)C語(yǔ)法元素時(shí)都要在其前面加上偽包前綴,比如C.uint和上面代碼中的C.print、C.free等。
我們?nèi)绾蝸?lái)編譯這個(gè)go源文件呢?其實(shí)與"正常"Go源文件沒(méi)啥區(qū)別,依舊可以直接通過(guò)go build或go run來(lái)編譯和執(zhí)行。但實(shí)際編譯過(guò)程中,go調(diào)用了名為cgo的工具,cgo會(huì)識(shí)別和讀取Go源文件中的C元素,并將其提取后交給C編譯器編譯,最后與Go源碼編譯后的目標(biāo)文件鏈接成一個(gè)可執(zhí)行程序。這樣我們就不難理解為何Go源文件中的C代碼要用注釋包裹了,這些特殊的語(yǔ)法都是可以被Cgo識(shí)別并使用的。
二、在Go中使用C語(yǔ)言的類(lèi)型
1、原生類(lèi)型
* 數(shù)值類(lèi)型
在Go中可以用如下方式訪問(wèn)C原生的數(shù)值類(lèi)型:
復(fù)制代碼
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
復(fù)制代碼
Go的數(shù)值類(lèi)型與C中的數(shù)值類(lèi)型不是一一對(duì)應(yīng)的。因此在使用對(duì)方類(lèi)型變量時(shí)少不了顯式轉(zhuǎn)型操作,如Go doc中的這個(gè)例子:
復(fù)制代碼
func Random() int {
return int(C.random())//C.long -> Go的int
}
func Seed(i int) {
C.srandom(C.uint(i))//Go的uint -> C的uint
}
復(fù)制代碼
* 指針類(lèi)型
原生數(shù)值類(lèi)型的指針類(lèi)型可按Go語(yǔ)法在類(lèi)型前面加上*,比如var p *C.int。而void*比較特殊,用Go中的unsafe.Pointer表示。任何類(lèi)型的指針值都可以轉(zhuǎn)換為unsafe.Pointer類(lèi)型,而unsafe.Pointer類(lèi)型值也可以轉(zhuǎn)換為任意類(lèi)型的指針值。unsafe.Pointer還可以與uintptr這個(gè)類(lèi)型做相互轉(zhuǎn)換。由于unsafe.Pointer的指針類(lèi)型無(wú)法做算術(shù)操作,轉(zhuǎn)換為uintptr后可進(jìn)行算術(shù)操作。
* 字符串類(lèi)型
C語(yǔ)言中并不存在正規(guī)的字符串類(lèi)型,在C中用帶結(jié)尾'