快速上手GoCGO,掌握在Go里写C!

大家好,我是煎鱼。

成都创新互联主打移动网站、成都网站建设、成都网站制作、网站改版、网络推广、网站维护、主机域名、等互联网信息服务,为各行业提供服务。在技术实力的保障下,我们为客户承诺稳定,放心的服务,根据网站的内容与功能再决定采用什么样的设计。最后,要实现符合网站需求的内容、功能与设计,我们还会规划稳定安全的技术方案做保障。

最近因为各种奇怪的原因,接触到了 Go 特色之一 CGO。这方面的相关内容也相对少一些,给大家抛砖引玉。

图片来源于 marlin

毕竟很多跨语言调用,还是会依赖 CGO 这个特性。希望大家在真正要用时有个前置知识垫肚子。

CGO 是什么

CGO 就是 C 和 Go,两个编程语言。指的是能够创建调用 C 代码的 Go 包。对照着 Go 代码中的 “C”:

package main

import "C"

func main() {}

一旦程序中出现 import "C",则意味着开启 CGO 特性。在进行 go build 等阶段时,将会调用 C 编译器(通常是 gcc 或 clang)。

CGO 对应的环境变量是 CGO_ENABLED,设置为 1 则开启 CGO,为 0 则关闭 CGO。

编译命令如下:

CGO_ENABLED=0 go build -o hellojy main.go

当然,对于默认值。该环境变量值为 1,C 编译器也是使用 gcc。我们可以通过 go env 看到:

一旦关闭就会影响 CGO 编译。需要特别留意,交叉编译时会默认关闭 CGO。

CGO 快速上手

最小 Demo

先来一个 CGO 的 Go 例子:

package main

//#include 
import "C"

func main() {
 s := C.CString("hello world.")
 C.puts(s)
}

运行 go run main.go,输出结果:

hello world.

声明 C 注解

如果你没有了解过 CGO,看到上面的例子,可能会有好几个疑问。

首先是 include:

//#include 
import "C"

import "C" 我们懂,是导入 C 的伪包。前面的注解是什么?

无论是:

//#include 

又或是:

/*
#include 
#include 
*/

实际上这是导入 C 前的注解,注解内容可以包含任何 C 代码,例如:函数、变量的声明定义、库引用等。(该注解要紧挨导入语句)

回到 Demo 本身,如果我们去掉 //#include ,再运行会出现如下报错:

# command-line-arguments
./main.go:7:2: could not determine kind of name for C.puts

去掉后,语句 C.puts(s) 将无法运行。

实际上 stdio.h 的全称是:standard input output.header(标准输入输出头文件)。该文件大都是些输入输出函数的声明,引用了这库,就能使用 C 的 puts 方法。

其他同理,你在注解中声明、定义的东西,均可以在 Go 代码中通过 C 这个伪包来引用和调用。

其次像是 CString 方法,属于在 Go 和 C 类型之间需要复制数据的特殊函数,伪包 C 有进行预定义。

例如:

func C.CString(string) *C.char
func C.CBytes([]byte) unsafe.Pointer
func C.GoString(*C.char) string
func C.GoStringN(*C.char, C.int) string
func C.GoBytes(unsafe.Pointer, C.int) []byte

Go 和 C 类型对照

Go 官方有提供一份基础类型的对照表,大家可以参照来使用和理解。

如下:

C 语言类型

CGO 类型

Go语言类型

char

C.char

byte

singed char

C.schar

int8

unsigned char

C.uchar

uint8

short

C.short

int16

unsigned short

C.ushort

uint16

int

C.int

int32

unsigned int

C.uint

uint32

long

C.long

int32

unsigned long

C.ulong

uint32

long long int

C.longlong

int64

unsigned long long int

C.ulonglong

uint64

float

C.float

float32

double

C.double

float64

size_t

C.size_t

uint

注意事项

使用 CGO,除了会带来一定的性能损耗外。需要特别注意的是:内存泄露。因为 Go 是带垃圾回收机制的编程语言,而使用了 C 后,需要手动的管理内存。

还是这个 Demo:

package main

//#include 
import "C"

func main() {
 s := C.CString("hello world.")
 C.puts(s)
}

如果这是一个常驻进程,也没有任何释放动作。用 C.CString 方法所申请的变量 s 就会泄露。

因此与 “C” 相关的变量创建,需要进行手动的内存管理。正确的代码如下:

/*
#include 
#include 
*/
import "C"
import (
 "unsafe"
)

func main() {
 b := C.CString("hello world.")
 C.puts(b)
 C.free(unsafe.Pointer(b))
}

需要调用 C.free 方法进行主动的内存释放。如果该程序自然结束,也会自动回收。

总结

在今天这篇文章中,我们介绍了 Go 语言中 CGO 的基础知识和快速入门。整体上,只要适应了写法,CGO 的用法就不算太麻烦。

需要特别注意手动内存管理、性能损耗等多方面的制约。后续我们也会继续深入 CGO 方面的内容。

网页标题:快速上手GoCGO,掌握在Go里写C!
转载来源:http://www.gawzjz.com/qtweb2/news18/1518.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联