Search
|
cgo
Tips for interfacing with C code and libraries using cgo.
IntroductionFirst, 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 basicsIf 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 CIt is possible to call both top-level Go functions and function variables from C code invoked from Go code using cgo. Global functionsGo 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 variablesThe 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 stringsGo 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:
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 slicesC 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:
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 PitfallsStruct Alignment IssuesAs 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 preambleIf 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;). |