在Golang中使用C語言代碼實(shí)例
cgo 使得在 Golang 中可以使用 C 代碼。
Hello World
為了有一個(gè)較為直觀的了解,我們來看一個(gè)簡單的例子,創(chuàng)建文件 main.go:
package main
/*
#include <stdio.h>
void sayHi() {
printf("Hi");
}
*/
import "C"
func main() {
C.sayHi()
}
執(zhí)行程序:
go run main.go
程序執(zhí)行并輸出 hi(更多的范例可以見 $GOROOT/misc/cgo)。
Windows 下的準(zhǔn)備工作
如果想要在 Windows 上使用 cgo,那么需要安裝 gcc 編譯器,這里我使用 mingw-w64。
設(shè)置編譯和鏈接標(biāo)志
我們使用 import “C” 導(dǎo)入的是一個(gè)偽包(pseudo-package),我們通過其來使用 C 代碼。在 import “C” 之前,緊跟著 import “C” 的注釋可以包括:
1.編譯器和鏈接器標(biāo)志
2.C 代碼
我們可以通過 #cgo 指令來設(shè)置編譯器和鏈接器標(biāo)志,例如:
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
附帶提及一點(diǎn)的是,這些指令中可以包含構(gòu)建約束(build constraint),詳細(xì)內(nèi)容見:http://golang.org/pkg/go/build/#hdr-Build_Constraints。
常用的 #cgo 指令有:
1.CPPFLAGS、CFLAGS 指令被用于編譯當(dāng)前包中的 C 文件(任何的 .c、.s、.S 文件)
2.CPPFLAGS、CXXFLAGS 指令被用于編譯當(dāng)前包中的 C++ 文件(任何的 .cpp、.cc、.cxx 文件)
3.LDFLAGS 指令用于指定鏈接器標(biāo)志
4.pkg-config 指令用于通過 pkg-config 工具獲取編譯器和鏈接器標(biāo)志(例如:#cgo pkg-config: png cairo)
Golang 引用 C
結(jié)構(gòu)體上需要注意的點(diǎn):
1.C 結(jié)構(gòu)體的域名稱如果為 Golang 的關(guān)鍵字時(shí),訪問時(shí)需要在域名稱前面加上 _。比如說,C 中有一個(gè)結(jié)構(gòu)體變量 x,此變量對(duì)應(yīng)的結(jié)構(gòu)體中有一個(gè)域 type,那么在 Golang 中需要通過 x._type 來訪問 type 域
2.結(jié)構(gòu)體的位域、非對(duì)齊數(shù)據(jù)等無法在 Golang 中表示時(shí)會(huì)被忽略
3.Golang 結(jié)構(gòu)體中不能使用 C 類型的域
標(biāo)準(zhǔn)的 C 數(shù)值類型對(duì)應(yīng):
1.C.char
2.C.schar(signed char)
3.C.uchar(unsigned char)
4.C.short
5.C.ushort(unsigned short)
6.C.int
7.C.uint(unsigned int)
8.C.long
9.C.ulong(unsigned long)
10.C.longlong(long long)
11.C.ulonglong(unsigned long long)
12.C.float
13.C.double
任何的 C 函數(shù)(包括 void 函數(shù))都可以返回一個(gè)返回值和 C 的 errno 變量(作為錯(cuò)誤):
n, err := C.sqrt(-1)
_, err := C.voidFunc()
直接調(diào)用 C 函數(shù)指針目前還無法支持。
有一些特殊的函數(shù)可以用于 C 類型和 Golang 類型之間轉(zhuǎn)換(通過數(shù)據(jù)拷貝的方式),偽定義如下:
// Golang 的字符串轉(zhuǎn)為 C 字符串
// C 的字符串是使用 malloc 分配的,因此,此函數(shù)的調(diào)用者
// 需要調(diào)用 C.free 來釋放內(nèi)存
func C.CString(string) *C.char
// 轉(zhuǎn)換 C 字符串到 Golang 字符串
func C.GoString(*C.char) string
// 轉(zhuǎn)換一定長度的 C 字符串到 Golang 字符串
func C.GoStringN(*C.char, C.int) string
// 轉(zhuǎn)換一塊 C 內(nèi)存區(qū)域到 Golang 的字節(jié)數(shù)組中去
func C.GoBytes(unsafe.Pointer, C.int) []byte
其他需要注意的點(diǎn):
1.C 語言中的 void* 對(duì)應(yīng) unsafe.Pointer
2.C 語言中的結(jié)構(gòu)、聯(lián)合、枚舉類型(而非變量),在 Golang 中需要加上 struct_、union_、enum_ 前綴訪問。由于 Golang 中沒有聯(lián)合這種數(shù)據(jù)類型,因此 C 的聯(lián)合在 Golang 中被表示為字節(jié)數(shù)組
3.和 C 語言等價(jià)的那些類型是不可以導(dǎo)出的
相關(guān)文章
Go語言的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)JSON
本文主要介紹了Go語言的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)JSON,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實(shí)例詳解
這篇文章主要介紹了Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-02-02go local history本地歷史恢復(fù)代碼神器
這篇文章主要為大家介紹了go local history本地歷史恢復(fù)代碼神器的使用功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01go語言使用Casbin實(shí)現(xiàn)角色的權(quán)限控制
Casbin是用于Golang項(xiàng)目的功能強(qiáng)大且高效的開源訪問控制庫。本文主要介紹了go語言使用Casbin實(shí)現(xiàn)角色的權(quán)限控制,感興趣的可以了解下2021-06-06Golang巧用defer進(jìn)行錯(cuò)誤處理的方法
錯(cuò)誤處理是程序的重要組成部分,有效且優(yōu)雅的處理錯(cuò)誤是大多數(shù)程序員的追求,下面這篇文章主要給大家介紹了關(guān)于Golang中巧用defer進(jìn)行錯(cuò)誤處理的方法,文中通過示例介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-05-05Golang將Map的鍵值對(duì)調(diào)的實(shí)現(xiàn)示例
本文主要介紹了Golang將Map的鍵值對(duì)調(diào)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02Go實(shí)現(xiàn)map轉(zhuǎn)json的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何利用Go語言實(shí)現(xiàn)map轉(zhuǎn)json的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-09-09