Pass struct and array of structs to C function from Go

tacobot picture tacobot · Nov 11, 2013 · Viewed 9.9k times · Source

Stuck with this problem. Able to get only the first member of passed structure... What I do wrong? And what is the right way to pass the structure from Go to C?

This is my example of how it doesn't work:

package main

/*
#include <stdio.h>

typedef struct {
    int a;
    int b;
} Foo;

void pass_array(Foo **in) {
    int i;

    for(i = 0; i < 2; i++) {
        fprintf(stderr, "[%d, %d]", in[i]->a, in[i]->b);
    }
    fprintf(stderr, "\n");
}

void pass_struct(Foo *in) {
    fprintf(stderr, "[%d, %d]\n", in->a, in->b);
}

*/
import "C"

import (
    "unsafe"
)

type Foo struct {
    A int
    B int
}

func main() {

    foo := Foo{25, 26}
    foos := []Foo{{25, 26}, {50, 51}}

    // wrong result = [25, 0]
    C.pass_struct((*_Ctype_Foo)(unsafe.Pointer(&foo)))

    // doesn't work at all, SIGSEGV
    // C.pass_array((**_Ctype_Foo)(unsafe.Pointer(&foos[0])))

    // wrong result = [25, 0], [50, 0]
    out := make([]*_Ctype_Foo, len(foos))
    out[0] = (*_Ctype_Foo)(unsafe.Pointer(&foos[0]))
    out[1] = (*_Ctype_Foo)(unsafe.Pointer(&foos[1]))
    C.pass_array((**_Ctype_Foo)(unsafe.Pointer(&out[0])))
}

Answer

Nick Craig-Wood picture Nick Craig-Wood · Nov 11, 2013

The problem is that Foo and _Ctype_Foo are different structures.

I would guess you are running on 64 bit. Note that int is 64 bit in go, but is quite likely to be 32 bit in C.

If I change the definition of Foo to this then it works on my machine (64 bit linux)

type Foo struct {
    A int32
    B int32
}

However I would say that is a recipe for trouble - make your Go and C code use the same structure with

type Foo _Ctype_Foo