博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C?Go?Cgo![翻译]
阅读量:7043 次
发布时间:2019-06-28

本文共 2244 字,大约阅读时间需要 7 分钟。

hot3.png

  • 原文:
  • 中文:

Cgo允许在Go包中调用C代码。如果Go代码含有特殊的cgo语法,可以通过cgo生成相应的Go和C文件,它们可以被编译到一个Go包中。

以一个例子开始,下面的Go包提供了 RandomSeed 两个函数,它们是基于C语言的 randomsrandom 函数的实现。

package rand/*#include 
*/import "C"func Random() int { return int(C.random())}func Seed(i int) { C.srandom(C.uint(i))}

我们从 import 语句开始,讲解相关的代码。

rand 包导入了一个 "C" 包,但是这个包并不是由Go标准库提供。因为 C 包是Cgo工具生成的一个虚拟包,它映射到C语言的名字空间。

rand 包中有几个地方使用了 C 包: C.randomC.srandomC.uint(i)import 语句。

Random 函数调用C语言标准库中的 random 函数,然后返回结果。 在C语言中,random 返回的结果为 long 类型,对应cgo生成的 C.long。在函数返回前我们必须将C类型转换为Go类型。

func Random() int {    return int(C.random())}

下面是一个等价的实现,为了更好说明类型转换的使用,这里使用了一个临时变量。

func Random() int {    var r C.long = C.random()    return int(r)}

Seed 函数进行相反的类型转换。它将传入的Go的 int 类型变量转换为C语言的 unsigned int,然后传入C语言的 srandom 函数。

func Seed(i int) {    C.srandom(C.uint(i))}

Cgo能够知道 unsigned int 对应 C.uint 类型。关于数值类型的详细说明可以参考。

到此为止,只有 import 语句的注释还没有解释。

/*#include 
*/import "C"

Cgo可以识别这个注释。注释中,任意以 #cgo 开头的行会被忽略,它们是cgo的扩展命令。 剩余的行在编译包的C代码时时,将被当作头文件处理。在这个例子中,虽然只有一个 #include 语句,但是可以包含任意的C语言代码。在构建包中C代码时,#cgo 规则可以指定用于编译和连接的选项。

有一点要注意:如果使用了 //export 规则,那么注释中的C代码将只能包含对应函数的声明(extern int f();), 而不能是对应函数的定义(int f() { return 1; })。使用 //export 规则,可以使Go函数被C语言函数调用。

关于 #cgo//export 的用法在 中有详细说明。

字符串相关

和Go语言不同,C语言没有明确的字符串类型。在C语言中,字符串表现为以 NULL 结尾的 char数组。

Go语言和C语言字符串之间的转换由以下函数完成:C.CStringC.GoStringC.GoStringN。这些函数函数在转换时均构造了一个字符串的副本。

这里是 Print 函数的另一个实现,它通过C语言的 stdio 标准库函数 fputs 将字符串写到标准输出:

package print// #include 
// #include
import "C"import "unsafe"func Print(s string) { cs := C.CString(s) C.fputs(cs, (*C.FILE)(C.stdout)) C.free(unsafe.Pointer(cs))}

Go语言的GC并不能管理C语言函数分配的内存。当使用 C.CString(使用C函数分配了内存)返回C字符串时, 必须要记得在完成后用 C.free 释放对应的内存。

C.CString 返回C语言字符串起始地址,因此在函数返回时将它转换为 unsafe.Pointer 类型,然后用 C.free释放对应内存空间。cgo中的一个常用习惯是在创建新内存后使用 defer 释放对应的内存 (特别是在后面代码很复杂时),下面是重写的 Print 函数:

func Print(s string) {    cs := C.CString(s)    defer C.free(unsafe.Pointer(cs))    C.fputs(cs, (*C.FILE)(C.stdout))}

构建cgo包

要构建cgo包,只要直接简单执行 或 命令。 go命令可以识别 "C" 虚拟包的语法,并且可以自动调用cgo生成相应的中间代码文件。

更多的Cgo资源

在 文档中有C包的更多的细节说明和构建的详细流程。 在Go目录树中的 演示了更全面的用法。

如果是简单的Cgo例子,可以参考 的 项目。 在 列表中有很多基于cgo的项目。

最后,如果想了解Cgo的工作原理,可以查看runtime包中的 代码。

转载于:https://my.oschina.net/chai2010/blog/119419

你可能感兴趣的文章
如何在 Linux 系统查询机器最近重启时间
查看>>
jQuery插件学习(二)
查看>>
地图服务器控件GIS Map Server v3.6发布,新增航空影像数据集功能
查看>>
Root WebApplicationContext
查看>>
Maven私服Nexus3.x环境构建操作记录
查看>>
java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)
查看>>
dubbo服务配置sentinel
查看>>
亚马逊下架一款智能玩具,几维安全提醒智能终端安全不容忽视
查看>>
计算机指令在CPU中的执行过程(图文版)
查看>>
理解 iOS 和 macOS 的内存管理
查看>>
Ajax (部分一)自己做的,总结页面向后台传Form值、单个值和后台向前台传一个或是一组值...
查看>>
web缓存技术
查看>>
集合知识点
查看>>
Linux快捷键
查看>>
文档对象模型DOM
查看>>
2019北京国际康复及个人健康博览会将在中国国际展览中心举办
查看>>
JVM——类加载机制(一)
查看>>
超清晰的 DNS 原理入门指南 (资源)
查看>>
大神笔记
查看>>
spring cloud构建java b2b2c 电子商务云商平台
查看>>