Tips for cgo

cgo的一些tips

基本类型

The standard C numeric types are available under the names C.char, C.schar (signed char), C.uchar (unsigned char), C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int), C.long, C.ulong (unsigned long), C.longlong (long long), C.ulonglong (unsigned long long), C.float, C.double, C.complexfloat (complex float), and C.complexdouble (complex double). The C type void* is represented by Go’s unsafe.Pointer. The C types __int128_t and __uint128_t are represented by [16]byte.

To access a struct, union, or enum type directly, prefix it with struct, union, or enum_, as in C.struct_stat.

The size of any C type T is available as C.sizeof_T, as in C.sizeof_struct_stat.

As Go doesn’t have support for C’s union type in the general case, C’s union types are represented as a Go byte array with the same length.

Go structs cannot embed fields with C types.

Any C function (even void functions) may be called in a multiple assignment context to retrieve both the return value (if any) and the C errno variable as an error (use _ to skip the result value if the function returns void). For example:

n, err := C.sqrt(-1)
_, err := C.voidFunc()

字符串类型转换

C.CStringC.GoString都会对原始数据做拷贝,不要忘记释放CString创建的内存:

// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char

// C string to Go string
func C.GoString(*C.char) string

// C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string

// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte

C.CString使用示例:

ch := C.CString(str)
defer C.free(unsafe.Pointer(ch))
....

数组的使用

Go切片转为C数组:

/*
#include <stdio.h>
void foo(double *arr, int len) {
	for(int i=0;i<len;i++) {
		printf("%f\n", arr[i]);
	}
}
*/
import "C"

func main() {
	arr := []float64{1, 2, 3, 4, 5}
	carr := (*C.double)(unsafe.Pointer(&arr[0]))
	C.foo(carr, C.int(len(arr)))

}

C数组转为Go切片

import "unsafe"
import "fmt"

/*
#include <stdio.h>
#include <stdlib.h>
double* get_array(int n) {
	double *arr;
	arr = (double*)malloc(n*sizeof(arr));
	for(int i=0;i<n;i++)
	{
		arr[i]=i;
	}
	return arr;
}
*/
import "C"

func main() {
	size := 10
	carr := C.get_array(C.int(size))
	defer C.free(unsafe.Pointer(carr))
	arr := (*[1 << 30]float64)(unsafe.Pointer(carr))[:size:size]
	fmt.Println(arr)
}

C指针操作

size := 10
carr := C.get_array(C.int(size))
defer C.free(unsafe.Pointer(carr))

// To go slice
arr := (*[1 << 30]float64)(unsafe.Pointer(carr))[:size:size]
for index := 0; index < size; index++ {
    // get value by C pointer operation
    value := *(*C.double)(unsafe.Pointer(uintptr(unsafe.Pointer(carr)) + uintptr(index)*unsafe.Sizeof(carr)))
    // get value by Go slice index
    gvalue := arr[index]
    fmt.Println(value, " == ", gvalue)
}

更多文档见https://golang.org/cmd/cgo/

Comments

comments powered by Disqus