cgo - go-wiki - Tips for interfacing with C code and libraries using cgo. - Go Language Community Wiki - Google Project Hosting

Golang

Search
for
cgo  
Tips for interfacing with C code and libraries using cgo.
Updated Mar 30, 2012 by [email protected]

Introduction

First, http://golang.org/cmd/cgo is the primary cgo documentation.

There is also a good intrduction article at http://golang.org/doc/articles/c_go_cgo.html.

The basics

If a Go source file imports "C", it is using cgo. The Go file will have access to anything appearing in the comment immediately preceding the line import "C", and will be linked against all other cgo comments in other Go files, and all C files included in the build process.

Note that there must be no blank lines in between the cgo comment and the import statement.

To access a symbol originating from the C side, use the package name C. That is, if you want to call the C function printf() from Go code, you write C.printf().

package cgoexample

/*
#include <stdio.h>
#include <stdlib.h>

void myprint(char* s) {
	printf("%s", s);
}
*/
import "C"

import "unsafe"

func Example() {
	cs := C.CString("Hello from stdio\n")
	C.myprint(cs)
	C.free(unsafe.Pointer(cs))
}

Calling Go functions from C

It is possible to call both top-level Go functions and function variables from C code invoked from Go code using cgo.

Global functions

Go makes its functions available to C code through use of a special //export comment.

package gocallback

import "fmt"

/*
#include <stdio.h>

extern void AGoFunction();

void ACFunction() {
	printf("ACFunction()\n");
	AGoFunction();
}
*/
import "C"

//export AGoFunction
func AGoFunction() {
	fmt.Println("AGoFunction()")
}

func Example() {
	C.ACFunction()
}

Function variables

The following code shows an example of invoking a Go callback from C code. Go passes the function variable to the CGo code by calling CallMyFunction(). CallMyFunction() invokes the callback by sending it back into the Go code, with the desired parameters, for unpacking and calling.

package gocallback

import (
	"unsafe"
	"fmt"
)

/*
extern void go_callback_int(void* foo, int p1);

void CallMyFunction(void* pfoo) {
	go_callback_int(pfoo, 5);
}
*/
import "C"

//export go_callback_int
func go_callback_int(pfoo unsafe.Pointer, p1 C.int) {
	foo := *(*func(C.int))(pfoo)
	foo(p1)
}

func MyCallback(x C.int) {
	fmt.Println("callback with", x)
}
//we store it in a global variable so that the garbage collector doesn't clean up the memory for any temporary variables created.
var MyCallbackFunc = MyCallback

func Example() {
	C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc))
}

Go strings and C strings

Go strings and C strings are different. Go strings are the combination of a length and a pointer to the first character in the string. C strings are just the pointer to the first character, and are terminated by the first instance of the null character, '\0'.

Go provides means to go from one to another in the form of the following three functions:

  • func C.CString(goString string) *C.char
  • func C.GoString(cString *C.char) string
  • func C.GoStringN(cString *C.char, length C.int) string

One important thing to remember is that C.CString() will allocate a new string of the appropriate length, and return it. That means the C string is not going to be garbage collected and it is up to you to free it. A standard way to do this follows.

// #include <stdlib.h>
import "C"
import "unsafe"
...
	var cmsg *C.char = C.CString("hi")
	defer C.free(unsafe.Pointer(cmsg))
	// do something with the C string

Of course, you aren't required to use defer to call C.free(). You can free the C string whenever you like, but it is your responsibility to make sure it happens.

Turning C arrays into Go slices

C arrays are typically either null-terminated or have a length kept elsewhere.

Go provides the following function to make a new Go byte slice from a C array:

  • func C.GoBytes(cArray unsafe.Pointer, length C.int) []byte

To create a Go slice backed by a C array (without copying the original data), one needs to acquire this length at runtime and use reflect.SliceHeader.

import "C"
import "unsafe"
...
        var theCArray *TheCType := C.getTheArray()
        length := C.getTheArrayLength()
        var theGoSlice []TheCType
        sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&theGoSlice)))
        sliceHeader.Cap = length
        sliceHeader.Len = length
        sliceHeader.Data = uintptr(unsafe.Pointer(&theCArray[0]))
        // now theGoSlice is a normal Go slice backed by the C array

It is important to keep in mind that the Go garbage collector will not interact with this data, and that if it is freed from the C side of things, the behavior of any Go code using the slice is nondeterministic.

Common Pitfalls

Struct Alignment Issues

As Go dosen't support packed struct (e.g., structs where maximum alignment is 1 byte), you can't use packed C struct in Go. Even if you program passes compilation, it won't do what you want. To use it, you have to read/write the struct as byte array/slice.

//export and definition in preamble

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; } or int n;).