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. 【算法复习】codevs1022 匈牙利算法

    题目描述 Description 有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地.如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分重叠)这个陆地,那么最多可以覆盖多少陆地面积.   ...

  2. Valid Parentheses - LeetCode

    目录 题目链接 注意点 解法 小结 题目链接 Valid Parentheses - LeetCode 注意点 考虑输入为空的情况 解法 解法一:如果是'('.'{'.'['这三者就入栈,否则就判断栈 ...

  3. 解题:POI 2006 PRO-Professor Szu

    题面 这个题是比较套路的做法啦,建反图后缩点+拓扑排序嘛,对于所有处在$size>=2$的SCC中的点都是无限解(可以一直绕) 然后注意统计的时候的小细节,因为无限解/大解也要输出,所以我们把这 ...

  4. 解题:POI 2007 Tourist Attractions

    题面 事实上这份代码在洛谷过不去,因为好像要用到一些压缩空间的技巧,我并不想(hui)写(捂脸) 先预处理$1$到$k+1$这些点之间相互的最短路和它们到终点的最短路,并记录下每个点能够转移到时的状态 ...

  5. centos7添加虚拟IP

    1.在网络配置文件中添加虚拟IP,vi /etc/sysconfig/network-scripts/ifcfg-eno16777736 TYPE="Ethernet" BOOTP ...

  6. git 生成公匙私匙

    直接 ssh-keygen -t rsa -C "*********@qq.com"也行 git config --global user.name “用户名” 用户名随便起!你能 ...

  7. D. Monitor Educational Codeforces Round 28

    http://codeforces.com/contest/846/problem/D 二分答案 适合于: 判断在t时候第一次成立 哪个状态是最小代价 #include <cstdio> ...

  8. 目标检测应用化之web页面(YOLO、SSD等)

    在caffe源码目录下的examples下面有个web_demo演示代码,其使用python搭建了Flask web服务器进行ImageNet图像分类的演示. 首先安装python的依赖库:pip i ...

  9. 企业级镜像管理系统Harbor

    Harbor简介 在说harbor之前,我们首先说一说直接使用docker registry的一些缺陷: 缺少认证机制,任何人都可以随意拉取及上传镜像,安全性缺失 缺乏镜像清理机制,镜像可以push却 ...

  10. python---基础知识回顾(十)进程和线程(多线程)

    前戏:多线程了解 使用多线程处理技术,可以有效的实现程序并发,优化处理能力.虽然进程也可以在独立的内存空间并发执行,但是生成一个新的进程必须为其分配独立的地址空间,并维护其代码段,堆栈段和数据段等,这 ...