To use existing C code, made by us or by someone else, we need to call C from Go. Let's perform a quick, complete example, where we are printing a string to the standard output using just C functionalities:
package main
/*
#include <stdio.h>
#include <stdlib.h>
void customPrint(char* s) {
printf("%s ", s);
}
*/
import "C"
import "unsafe"
func main() {
s := C.CString(`Printing to stdout with CGO
Using <stdio.h> and <stdlib.h>`)
defer C.free(unsafe.Pointer(s))
C.customPrint(s)
}
We are importing two C core libraries here, which are as follows:
- stdio.h : This contains the input and output methods. We are using printf.
- stdlib.h: This contains general functions, including memory management.
Looking at the preceding code, we notice that the variable that we are printing is not a normal Go string, but rather, it is obtained by the C.CString function that takes a string and returns a slice of char, because that's how strings are treated in C. The function is defined as follows:
func C.CString(string) *C.char
The second thing we can observe is that we are deferring a call to C.free, passing the s variable that we defined, but converted to a different type. This function call is essential since the language is not garbage collected and, in order to free the memory used, the application needs to specifically call the C free function. This function receives a generic pointer, which is represented by the unsafe.Pointer type in Go. According to the Go documentation, the following applies:
This is exactly what we are doing, because the type of the string variable is the *C.char pointer.