aboutsummaryrefslogtreecommitdiff
path: root/content/cgo.article
diff options
context:
space:
mode:
Diffstat (limited to 'content/cgo.article')
-rw-r--r--content/cgo.article151
1 files changed, 151 insertions, 0 deletions
diff --git a/content/cgo.article b/content/cgo.article
new file mode 100644
index 0000000..0697395
--- /dev/null
+++ b/content/cgo.article
@@ -0,0 +1,151 @@
+# C? Go? Cgo!
+17 Mar 2011
+Tags: cgo, technical
+Summary: How to use cgo to let Go packages call C code.
+OldURL: /c-go-cgo
+
+Andrew Gerrand
+
+## 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](https://golang.org/cmd/cgo) 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 `#cgo` directives 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 `//export` directives to make Go functions accessible to C code.
+
+The `#cgo` and `//export` directives are documented in the [cgo documentation](https://golang.org/cmd/cgo/).
+
+## 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.CString`,
+`C.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`](https://golang.org/pkg/unsafe/#Pointer)
+and release the memory allocation with `C.free`.
+A common idiom in cgo programs is to [`defer`](https://golang.org/doc/articles/defer_panic_recover.html)
+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`](https://golang.org/cmd/go/#Compile_packages_and_dependencies)
+or [`go install`](https://golang.org/cmd/go/#Compile_and_install_packages_and_dependencies) as usual.
+The go tool recognizes the special `"C"` import and automatically uses cgo for those files.
+
+## More cgo resources
+
+The [cgo command](https://golang.org/cmd/cgo/) documentation has more
+detail about the C pseudo-package and the build process.
+The [cgo examples](https://golang.org/misc/cgo/) 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](https://golang.org/src/runtime/cgocall.go).