diff options
Diffstat (limited to 'content/c-go-cgo.article')
-rw-r--r-- | content/c-go-cgo.article | 74 |
1 files changed, 58 insertions, 16 deletions
diff --git a/content/c-go-cgo.article b/content/c-go-cgo.article index 19a01f3..2ee6e92 100644 --- a/content/c-go-cgo.article +++ b/content/c-go-cgo.article @@ -6,9 +6,11 @@ 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. +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. +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 @@ -27,11 +29,20 @@ To lead with an example, here's a Go package that provides two functions - `Rand 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 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 `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: +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()) @@ -44,13 +55,17 @@ Here's an equivalent function that uses a temporary variable to illustrate the t 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`. +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 [[https://golang.org/cmd/cgo][cgo documentation]] for a complete list of these numeric type names. +Note that cgo knows the `unsigned`int` type as `C.uint`; +see the [[https://golang.org/cmd/cgo][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. @@ -59,9 +74,19 @@ The one detail of this example we haven't examined yet is the comment above the */ 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. +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. +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 [[https://golang.org/cmd/cgo/][cgo documentation]]. @@ -69,9 +94,12 @@ The `#cgo` and `//export` directives are documented in the [[https://golang.org/ 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. +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: +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 @@ -86,9 +114,17 @@ This next example implements a `Print` function that writes a string to standard 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`. +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 [[https://golang.org/pkg/unsafe/#Pointer][`unsafe.Pointer`]] and release the memory allocation with `C.free`. A common idiom in cgo programs is to [[https://golang.org/doc/articles/defer_panic_recover.html][`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`: +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 [[https://golang.org/pkg/unsafe/#Pointer][`unsafe.Pointer`]] +and release the memory allocation with `C.free`. +A common idiom in cgo programs is to [[https://golang.org/doc/articles/defer_panic_recover.html][`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) @@ -98,10 +134,16 @@ The call to `C.CString` returns a pointer to the start of the char array, so bef * Building cgo packages -To build cgo packages, just use [[https://golang.org/cmd/go/#Compile_packages_and_dependencies][`go`build`]] or [[https://golang.org/cmd/go/#Compile_and_install_packages_and_dependencies][`go`install`]] as usual. The go tool recognizes the special `"C"` import and automatically uses cgo for those files. +To build cgo packages, just use [[https://golang.org/cmd/go/#Compile_packages_and_dependencies][`go`build`]] +or [[https://golang.org/cmd/go/#Compile_and_install_packages_and_dependencies][`go`install`]] as usual. +The go tool recognizes the special `"C"` import and automatically uses cgo for those files. * More cgo resources -The [[https://golang.org/cmd/cgo/][cgo command]] documentation has more detail about the C pseudo-package and the build process. The [[https://golang.org/misc/cgo/][cgo examples]] in the Go tree demonstrate more advanced concepts. +The [[https://golang.org/cmd/cgo/][cgo command]] documentation has more +detail about the C pseudo-package and the build process. +The [[https://golang.org/misc/cgo/][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 [[https://golang.org/src/runtime/cgocall.go][cgocall.go]]. +Finally, if you're curious as to how all this works internally, +take a look at the introductory comment of the runtime package's [[https://golang.org/src/runtime/cgocall.go][cgocall.go]]. |