2013-11-11 3 views
6

Застрял с этой проблемой. Возможность получить только первый член пройденной структуры ... Что я делаю неправильно? И какой правильный способ передать структуру от Go to C?Передача структуры и массива структур в функцию C из Go

Это мой пример того, как он не работает:

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]))) 
} 

ответ

6

Проблема заключается в том, что Foo и _Ctype_Foo разные структуры.

Я бы предположил, что вы работаете на 64 бит. Обратите внимание, что int 64 бит в ходу, но вполне вероятно, будет 32 бита в С.

Если изменить определение Foo на это, то он работает на моей машине (64 бит Linux)

type Foo struct { 
    A int32 
    B int32 
} 

Однако я бы сказал, что это рецепт для неприятностей - сделать ваш Go и C код использовать ту же структуру, с

type Foo _Ctype_Foo 
+0

согласен с заключением об использовании типа C в явном виде. Просто примечание, 'int' golang не обязательно 64 бит; это * не менее * 32bit: http://golang.org/pkg/builtin/#int – Jonno

4

Я знаю, что это довольно старая тема, но я наткнулся на него. Вот измененная (правильная) версия с некоторыми дополнительными манипуляциями с земли C на структурах Go.

package main 

/* 
#include <stdio.h> 

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

void pass_struct(Foo *in) { printf("%d : %d\n", in->a, in->b); } 

void pass_array(Foo **in, int len) { 
    for(int i = 0; i < len; i++) { 
     pass_struct(in[i]); 
     in[i]->a += 1; 
     in[i]->b += 1; 
    } 
} 
*/ 
import "C" 

import (
    "fmt" 
    "unsafe" 
) 

type Foo struct{ a, b int32 } 

func main() { 
    foo := Foo{10, 20} 
    foos := []*Foo{&Foo{1, 2}, &Foo{3, 4}} 

    fmt.Println("from C land") 
    C.pass_struct((*C.Foo)(unsafe.Pointer(&foo))) 
    C.pass_array((**C.Foo)(unsafe.Pointer(&foos[0])), C.int(len(foos))) 
    fmt.Println("a & b should have incremented with 1") 

    fmt.Println("from Go land") 
    for _, foo := range foos { 
     fmt.Printf("%d : %d\n", foo.a, foo.b) 
    } 
} 

Выход:

from C land 
10 : 20 
1 : 2 
3 : 4 
a & b should have incremented with 1 
from Go land 
2 : 3 
4 : 5 
+0

Когда я пытаюсь запустить этот код, я получаю следующую ошибку: panic: ошибка времени выполнения: аргумент cgo имеет указатель Go to Go go pointer –