go语言的cgo简单教程

编程入门 行业动态 更新时间:2024-10-21 07:26:24

go<a href=https://www.elefans.com/category/jswz/34/1770116.html style=语言的cgo简单教程"/>

go语言的cgo简单教程

目前Go语言有2套编译器:GC和gccgo。其中GC提供的cgo支持C语言,gccgo支持C/C++。 此外,SWIG从2.0.1之后也对go语言提供支持,可以支持C++的类和回调。Go官方提供cmd/go命令, 可以很好的支持cgo,swig支持目前还在完善之中。
本文将简要介绍基于cgo集成C/C++库,适用平台: Linux/Windows。
1. Hello, 世界
// hello.go package main
import "fmt"
func main() { fmt.Printf("Hello, 世界\n") }
由于go编译速度很快,并且cmd/go支持远程get第三方库,go可以方便的作为脚本语言使用。 运行上面的程序, 可以直接输入: go run hello.go。
2. 基于CGO的 Hello, 世界
package main
/* #include <stdio.h> */ import "C"
func main() { C.puts(C.CString("Hello, 世界\n")) }
其中 import "C" 前注释中可以导入C语言 函数/变量/宏 等到一个虚拟的 "C" 包中。 我们可以直接使用C.前缀访问C中的函数。
当前的例子中,使用C的puts函数输出"Hello, 世界"。之所以没有使用C语言经典的printf函数, 是因为printf的参数是可变的,而cgo不支持访问你可变参数的函数。
如果需要使用printf函数,需要再做一次包装。
3. 基于C语言printf的 Hello, 世界
package main
/* #include <stdio.h>
static void myPrint(const char* msg) { printf("myPrint: %s", msg); } */ import "C"
func main() { //C.puts(C.CString("Hello, 世界\n")) //C.printf(C.CString("Hello, 世界\n")) // error C.myPrint(C.CString("Hello, 世界\n")) }
我们通过myPrint来屏蔽printf的可变参数特性。在 import "C" 定义的函数一般建议定义为static。
4. CGO常用的函数
CGO内置了一些常用的函数:
// Go string to C string // The C string is allocated in the C heap using malloc. // It is the caller's responsibility to arrange for it to be // freed, such as by calling C.free. func C.CString(string) *C.char
// C string to Go string func C.GoString(*C.char) string
// C string, length to Go string func C.GoStringN(*C.char, C.int) string
// C pointer, length to Go []byte func C.GoBytes(unsafe.Pointer, C.int) []byte
我们前面的例子就是使用了 C.CString 将go的字符串转换为C语言的char*类型。 C.CString 返回的空间由C语言的malloc分配,使用完毕后需要用free释放。
5. 释放C.CString分配的空间
package main
/* #include <stdio.h> #include <stdlib.h> */ import "C" import "unsafe"
func main() { cStr := C.CString("Hello, 世界\n") defer C.free(unsafe.Pointer(cStr)) C.puts(C.CString("Hello, 世界\n")) }
C.CString返回的是C语言的char*类型,对应go语言的*C.char。 C语言的free参数是void*类型, 对应go语言的unsafe.Pointer。由于go语言禁止2种不同类型的隐式转换,因此用C.free时需要手工转换 类型,对应代码 unsafe.Pointer(cStr)。这样cStr的空间就不会出现内存泄露了。
另外,使用CGO时,一般都会导入"unsafe"包。"unsafe"中提供了一些类似C语言中的底层工具:
func Alignof(v ArbitraryType) uintptr func Offsetof(v ArbitraryType) uintptr func Sizeof(v ArbitraryType) uintptr type ArbitraryType type Pointer
6. 常见的C/go类型转换
使用CGO时,c和go之间的基本数据类型转换是经常遇到的一个问题。
整数/浮点数 转换:
// c -> go i_go = int(C.i_c) f32_fo = float32(C.float_c) f64_fo = float64(C.double_c)
// go -> c i_c = C.int(i_go) float_c = C.float(f32_go) double_c = C.double(f64_go)
字符串转换:
// c -> go str_go = C.GoString(C.str_c)
// go -> c str_c = C.CString(str_go)
指针转换: // c -> go p_int_go = (*int)(unsafe.Pointer(C.p_int)) // go -> c p_int_c = (*C.int)(unsafe.Pointer(&myIntSlice[0]))
比如要调用C语言的main函数(代码不能运行,只是为了说明字符串数组转换):
func CallMain(args []string) int { argc := C.int(len(args)) argv := make([]*C.char, len(args)) for i := 0; i < len(args); i++ { argv[i] = C.CString(args[i]) } rv := C.main(argc, (**C.char)(unsafe.Pointer(&argv))) return int(rv) }
如果是回调函数,需要在C中作一层封装(相对比较麻烦)。
7. 连接选项
可以使用#cgo扩展预处理命令指定CFLAGS/LDFLAGS。
比如go-gdal库的连接参数为: /* #include "go_gdal.h"
#cgo linux  pkg-config: gdal #cgo darwin pkg-config: gdal #cgo windows LDFLAGS: -lgdal.dll */ import "C"
#cgo之后可以跟系统命令,指定参数对应生效的系统。对于Linux等系统,可以直接使用pkg-config。
8. 集成C++库
目前cgo不识别C++语法。如果需要使用C++库,可以将C++库的API封装为C语言形式,然后编译为动态库。 根据动态库生成对于的导出lib和一个只有C API说明的头文件,然后可以导入go环境使用。
注: CGO的内容比较杂,而且需要搭建完备的开发环境,现整理一点,以后慢慢补充。 目前,笔者尝试过2个C库的go帮定, 读者可以参考。网址是:
/

/


原文转自:/

更多推荐

go语言的cgo简单教程

本文发布于:2024-03-09 09:15:27,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724576.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:语言   简单   教程   cgo

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!