Talk about cgo! again.

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Recently on the Kubernetes to integrate other team algorithm things, their algorithm is written in C, naturally I need to use CGO to invoke. This article has organized some functions in the process of using CGO, which are hereby collated and recorded.

1, passing a two-dimensional integer array to the C function

The C function needs to receive a two-dimensional integer array as a parameter,

extern bool xxx_func(int** _matrix);

The initial implementation is as follows:

goArray := [][]int{{1},{3,3},{3,3,2}}cArray := make([][]C.int, len(goArray))for i, _ := range goArray {     cArray[i] = make([]C.int, len(goArray[i]))     for j, _ := range goArray[i] {         cArray[i][j] = C.int(goArray[i][j])         }} C.xxx_func((**C.int)(unsafe.Pointer(&cArray[0][0]))) // 把该数组的首地址传递给c函数

Is that the way it's done? Of course not! Looking closely at the function, this function actually creates a slice, then stores n separate slices in it, and its memory address is not contiguous! Of course, this is true for go itself, but for C it is a big mistake, the memory address of the two-dimensional array in C must be contiguous (the two-dimensional array in C is actually a one-dimensional array, addressing differently). So it should be done as follows:

    • Assigns a slice of length n*m (N and m for rows and columns of a two-dimensional array)
    • Populate this slice with values from the two-dimensional array of Go
    • Pass this slice pointer to the C function

The first type of code is implemented as follows:

n, m := len(goArray), 0for _, row := range goArray {    if len(row) > m {        m = len(row)    }}cArray := make([]C.int, n*m)for i, row := range goArray {    for j, v := range row {        a[i * n + j] = v    }  

Then run, found cannot use &cArray[0] (type *C.int) as type **C.int in argument to func literal that the above operation is actually to convert the two-dimensional array of go to a one-dimensional array and then passed to the C function, but the C function to receive is a int** two-dimensional array, so error, the best solution is to change the C function parameters to receive int* a one-dimensional array.
But what if we can't change the parameters of the C function?
The second type of code implementation:

        cArray := make([]*C.int, len(goArray))        for i, row := range goArray {                p := (*C.int)(C.malloc(C.size_t(C.sizeof_int * len(row))))                cArray[i] = p                pa := (*[1 << 30]C.int)(unsafe.Pointer(p))                for j, v := range row {                        (*pa)[j] = C.int(v)                }        }

Here, we assign a source-sized c.int array for each row of the Goarray, and give the pointer p to CArray,
The P type *C.int is then converted to *[1<<30]C.int a type (pointing to a large array of c.int types), but there are two questions to note:

    • Memory release for C.malloc ()
    • We row have allocated an array for each row, but the array length information is missing! There's no problem with go, but for C, an array is just a pointer, and it doesn't know the length of the memory area through this pointer, you have to tell it, or write a struct that contains the pointer and length, which depends on the specific implementation of C.

The first method is recommended, because the memory release problem of CGO and C can toss you for a few days, unless you know clearly where to release and where not to release.

2, passing a string array to the C function

This is much simpler, but you need to be aware of the memory release. The code is as follows:

goString := []string{"w0", "w1", "w2", "w3"} cString := make([]*C.char, len(goString)) for i, _ := range goString {         cString[i] = C.CString(goString[i])         // 注意这个内存释放,该不该在调用完c函数之后释放,依赖于c那边的实现,这里要小心使用!        defer C.free(unsafe.Pointer(cString[i])) } C.xxx_func2((**C.char)(unsafe.Pointer(&cString[0])))

Official documentation on C.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

3, convert c string array to go string slice

//你必须清楚地知道返回的c字符串数组的长度func GoStrings(length int, argv **C.char) []string {        if argv == nil {                return nil        }        tmpslice := (*[1 << 30]*C.char)(unsafe.Pointer(argv))[:length:length]        gostrings := make([]string, length)        for i, s := range tmpslice {                gostrings[i] = C.GoString(s)        }        return gostrings}

C.gostring's Official document, really concise: (

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

Reference: https://golang.org/cmd/cgo/
CGO Wiki:https://github.com/golang/go/wiki/cgo
Google Big God more: https://groups.google.com/forum/#!topic/golang-nuts/Nb-nfVdAyF0

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.