- 相關推薦
Go與C語言的操作
Go有強烈的C背景,除了語法具有繼承性外,其設計者以及其設計目標都與C語言有著千絲萬縷的聯系。在Go與C語言互操作(Interoperability)方面,Go更是提供了強大的支持。尤其是在Go中使用C,你甚至可以直接在Go源文件中編寫C代碼,這是其他語言所無法望其項背的。下面是小編為大家帶來的Go與C語言的操作的知識,歡迎閱讀。
一、Go調用C代碼的原理
下面是一個短小的例子:
復制代碼
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))
}
復制代碼
與"正常"Go代碼相比,上述代碼有幾處"特殊"的地方:
1) 在開頭的注釋中出現了C頭文件的include字樣
2) 在注釋中定義了C函數print
3) import的一個名為C的"包"
4) 在main函數中居然調用了上述的那個C函數-print
沒錯,這就是在Go源碼中調用C代碼的步驟,可以看出我們可直接在Go源碼文件中編寫C代碼。
首先,Go源碼文件中的C代碼是需要用注釋包裹的,就像上面的include 頭文件以及print函數定義;
其次,import "C"這個語句是必須的,而且其與上面的C代碼之間不能用空行分隔,必須緊密相連。這里的"C"不是包名,而是一種類似名字空間的概念,或可以理解為偽包,C語言所有語法元素均在該偽包下面;
最后,訪問C語法元素時都要在其前面加上偽包前綴,比如C.uint和上面代碼中的C.print、C.free等。
我們如何來編譯這個go源文件呢?其實與"正常"Go源文件沒啥區別,依舊可以直接通過go build或go run來編譯和執行。但實際編譯過程中,go調用了名為cgo的工具,cgo會識別和讀取Go源文件中的C元素,并將其提取后交給C編譯器編譯,最后與Go源碼編譯后的目標文件鏈接成一個可執行程序。這樣我們就不難理解為何Go源文件中的C代碼要用注釋包裹了,這些特殊的語法都是可以被Cgo識別并使用的。
二、在Go中使用C語言的類型
1、原生類型
* 數值類型
在Go中可以用如下方式訪問C原生的數值類型:
復制代碼
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
復制代碼
Go的數值類型與C中的數值類型不是一一對應的。因此在使用對方類型變量時少不了顯式轉型操作,如Go doc中的這個例子:
復制代碼
func Random() int {
return int(C.random())//C.long -> Go的int
}
func Seed(i int) {
C.srandom(C.uint(i))//Go的uint -> C的uint
}
復制代碼
* 指針類型
原生數值類型的指針類型可按Go語法在類型前面加上*,比如var p *C.int。而void*比較特殊,用Go中的unsafe.Pointer表示。任何類型的指針值都可以轉換為unsafe.Pointer類型,而unsafe.Pointer類型值也可以轉換為任意類型的指針值。unsafe.Pointer還可以與uintptr這個類型做相互轉換。由于unsafe.Pointer的指針類型無法做算術操作,轉換為uintptr后可進行算術操作。
* 字符串類型
C語言中并不存在正規的字符串類型,在C中用帶結尾' 主站蜘蛛池模板: 塔城市| 九龙县| 雷山县| 喀什市| 封丘县| 阳春市| 五家渠市| 宁蒗| 黄山市| 荔浦县| 通江县| 嘉峪关市| 扶余县| 蓬莱市| 新密市| 自治县| 澎湖县| 泽州县| 扶余县| 体育| 涞水县| 鄂托克旗| 勃利县| 虞城县| 邹平县| 平顶山市| 繁昌县| 安泽县| 五常市| 大城县| 灯塔市| 沙河市| 新源县| 长沙县| 陵川县| 正安县| 宁陵县| 互助| 富宁县| 京山县| 西贡区|