C? Go? Cgo!

17 March 2011

Introduction

Cgo lets Go packages call C code. Given a Go source file written with some special features, cgo outputs Go and C files that can be combined into a single Go package.

To lead with an example, here's a Go package that provides two functions - Random and Seed - that wrap C's random and srandom functions.

package rand

/*
#include <stdlib.h>
*/
import "C" func Random() int {
return int(C.random())
} func Seed(i int) {
C.srandom(C.uint(i))
}

Let's look at what's happening here, starting with the import statement.

The rand package imports "C", but you'll find there's no such package in the standard Go library. That's because C is a "pseudo-package", a special name interpreted by cgo as a reference to C's name space.

The rand package contains four references to the C package: the calls to C.random and C.srandom, the conversion C.uint(i), and the import statement.

The Random function calls the standard C library's random function and returns the result. In C, random returns a value of the C type long, which cgo represents as the type C.long. It must be converted to a Go type before it can be used by Go code outside this package, using an ordinary Go type conversion:

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

Here's an equivalent function that uses a temporary variable to illustrate the type conversion more explicitly:

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

The Seed function does the reverse, in a way. It takes a regular Go int, converts it to the C unsigned int type, and passes it to the C function srandom.

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

Note that cgo knows the unsigned int type as C.uint; see the cgo documentation for a complete list of these numeric type names.

The one detail of this example we haven't examined yet is the comment above the import statement.

/*
#include <stdlib.h>
*/
import "C"

Cgo recognizes this comment. Any lines starting with #cgo followed by a space character are removed; these become directives for cgo. The remaining lines are used as a header when compiling the C parts of the package. In this case those lines are just a single #include statement, but they can be almost any C code. The #cgodirectives are used to provide flags for the compiler and linker when building the C parts of the package.

There is a limitation: if your program uses any //export directives, then the C code in the comment may only include declarations (extern int f();), not definitions (int f() { return 1; }). You can use //exportdirectives to make Go functions accessible to C code.

The #cgo and //export directives are documented in the cgo documentation.

Strings and things

Unlike Go, C doesn't have an explicit string type. Strings in C are represented by a zero-terminated array of chars.

Conversion between Go and C strings is done with the C.CStringC.GoString, and C.GoStringN functions. These conversions make a copy of the string data.

This next example implements a Print function that writes a string to standard output using C's fputs function from the stdio library:

package print

// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe" func Print(s string) {
cs := C.CString(s)
C.fputs(cs, (*C.FILE)(C.stdout))
C.free(unsafe.Pointer(cs))
}

Memory allocations made by C code are not known to Go's memory manager. When you create a C string with C.CString (or any C memory allocation) you must remember to free the memory when you're done with it by calling C.free.

The call to C.CString returns a pointer to the start of the char array, so before the function exits we convert it to an unsafe.Pointer and release the memory allocation with C.free. A common idiom in cgo programs is to defer the free immediately after allocating (especially when the code that follows is more complex than a single function call), as in this rewrite of Print:

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

Building cgo packages

To build cgo packages, just use go build or go install as usual. The go tool recognizes the special "C" import and automatically uses cgo for those files.

More cgo resources

The cgo command documentation has more detail about the C pseudo-package and the build process. The cgo examples in the Go tree demonstrate more advanced concepts.

Finally, if you're curious as to how all this works internally, take a look at the introductory comment of the runtime package's cgocall.go.

By Andrew Gerrand

Related articles

30 C? Go? Cgo!的更多相关文章

  1. 总结30个CSS3选择器

    或许大家平时总是在用的选择器都是:#id  .class  以及标签选择器.可是这些还远远不够,为了在开发中更加得心应手,本文总结了30个CSS3选择器,希望对大家有所帮助. 1 *:通用选择器 ;; ...

  2. 值得收藏!国外最佳互联网安全博客TOP 30

    如果你是网络安全从业人员,其中重要的工作便是了解安全行业的最新资讯以及技术趋势,那么浏览各大安全博客网站或许是信息来源最好的方法之一.最近有国外网站对50多个互联网安全博客做了相关排名,小编整理其中排 ...

  3. CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率

    CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率 当场景中有比较复杂的模型时,条件渲染能够加速对复杂模型的渲染. 条件渲染(Conditio ...

  4. 30分钟学会XAML

    1.狂妄的WPF 相对传统的Windows图形编程,需要做很多复杂的工作,引用许多不同的API.例如:WinForm(带控件表单).GDI+(2D图形).DirectX API(3D图形)以及流媒体和 ...

  5. Shell脚本编程30分钟入门

    Shell脚本编程30分钟入门 转载地址: Shell脚本编程30分钟入门 什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell_tut cd shell_t ...

  6. ViEmu 3.6.0 过期 解除30天限制的方法

    下载:链接: http://pan.baidu.com/s/1c2HUuWw 密码: sak8 删除下面2个地方 HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{B9CDA4 ...

  7. AlloyTouch全屏滚动插件发布--30秒搞定顺滑H5页

    原文链接:https://github.com/AlloyTeam/AlloyTouch/wiki/AlloyTouch-FullPage-Plugin 先验货 插件代码可以在这里找到. 注意,虽然是 ...

  8. C#求斐波那契数列第30项的值(递归和非递归)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...

随机推荐

  1. view的阴影效果shadowColor

    btn.layer.shadowColor = UIColor.blackColor().CGColor btn.layer.shadowOffset = CGSizeMake(5, 5) btn.l ...

  2. BZOJ 2878 【NOI2012】 迷失游乐园

    题目链接:迷失游乐园 这道题也没有传说中的那么难写吗→_→ 似乎有篇博客讲得特详细……附上链接:戳这里 如果这道题不是基环树,而就是一棵树的话,我们来考虑改怎么做.因为树上的路径只有向上.向下两种走法 ...

  3. Luogu1309 瑞士轮(分治,归并排序)

    Luogu1309 瑞士轮(分治,归并排序) Description 在双人对决的竞技性比赛,如乒乓球.羽毛球.国际象棋中,最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少,每场都紧张刺激,但偶然 ...

  4. zuul学习

    1.zuul可以代理界面所需的后端服务,可以解决CORS(Cross-Origion-Resource-Sharing)和认证问题(authentication)问题 2.zuul是使用ribbon来 ...

  5. 为什么只有一个元素的tuple要加逗号?

    如果要定义一个空的tuple,可以写成(): >>> t = () >>> t () 但是,要定义一个只有1个元素的tuple,如果你这么定义: >>& ...

  6. 解决Pytohn安装第三方库出现read timed out 问题

    输入pip --default-timeout=100 install -U Packages 如pip --default-timeout=100 install -U Pillow

  7. NATS_10:NATS服务配置文件详解

    尽管NATS可以无配置的运行,但也可以使用配置文件配置NATS服务的启动,在实际应用当中,一般都是通过使用配置文件来启动服务的. 1. 配置项包括 客户端监听器端口 Client listening ...

  8. rsync命令的基本使用

    rsync命令的基本使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. rsync服务软件是一款开源,高速的,数据同步(拷贝)工具. 一.rsync服务的特点 1>.本地拷贝 ...

  9. const引用与非const引用

    void print1(int a) { cout<<a<<endl; } void print2(const int& a) { cout<<a<& ...

  10. CF869 C 组合

    先吐槽下,题面套的物语系列欸.. 由于距离为3,那么必定两种颜色间要填入第3种颜色,否则就是单独点的情况,那么两两之间可以单独考虑而不影响答案,枚举两种颜色之间边数,计算一边的组合和另一边的排列,最后 ...