cgo, используя массив c struct и присваивая значение в go

У меня проблема при использовании cgo с массивом структур c.

Моя программа выглядит следующим образом:

У меня есть структура в c и содержит указатель на массив структур c.

В C я предоставляю функцию инициализации (принимаю два параметра: указатель на переменную и длину массива внутри переменной), чтобы выделить память переменной.

Затем In go я присваиваю значение этой переменной и присваиваю значение массиву в переменной. И в go я вызываю другую функцию C для использования этой переменной.

После того, как функция C справится с этим. Снова возьмите переменную и вернитесь к другой функции Go.

Когда я кодирую так, я иду к массиву вроде. type *C.struct не поддерживает индексацию.

Мой код выглядит следующим образом.

C:

тест.ч

typedef struct
{
    int     profileCnt;
    _profile   *profile;                      //pointer to profile array
}_profiles;
// variable using in Go


typedef struct
{
    int     profileId;              
    _name   userName;               
    char         *dateOfBirth;          
    int     stateFipsId;            
}_profile;

typedef struct
{
    char    first[32];
    char    last[32];
} _name;


void initializeProfiles(_profiles *profiles, int profileCount, bool create);
int doSomething _In_C( _profiles *profiles, int log);

тест.с

void initializeProfiles(_profiles *profiles, int profileCount, bool create)
{

    profiles->profileCnt = profileCount;                                                
//  initialize profiles struct & profile[] Array

    if (profileCount > 0)
    {
        if (create == true)
            profiles->profile = malloc(profileCount * sizeof *profiles->profile + 1);           //  allocate memory for profiles[numProfiles]

            for (int i = 0; i < profiles->profileCnt; i++)
            initializeProfile(&profiles->profile[i], create);

        if (create == false)
        {
            free(profiles->profile);
            profiles->profileCnt = 0;
        }
    }
    else
        profiles->profile = NULL;

} 

void initializeProfile(_profile *profile, bool create)
{
    if (create == true)
    {       
        profile->dateOfBirth = NULL;            
    }

    profile->profileId = 0;                 
    memset(profile->userName.first, '\0', sizeof(profile->userName.first));     
    memset(profile->userName.last, '\0', sizeof(profile->userName.last));       

    if (create == false)
    {
        if (profile->dateOfBirth != NULL)
            free(profile->dateOfBirth);
    }
}



int doSomething _In_C( _profiles *profiles, int log)
{

    /*  ===========================================



    */  ====   did something to that variable============================

    if (errStatus.code == _SUCCESS)
        return(_SUCCESS);
    else
        return(FAILURE);
}

Мой код GO

package main
//#cgo CFLAGS: -std=c99 -ggdb3 -O0 -Wall
//#cgo CFLAGS: -I../../include/common
//#cgo LDFLAGS: -L string.h
//#cgo LDFLAGS: -lstdc++ -lpthread -lm -lc -lssl -lcrypto
//#include <stdio.h>
//#include <stdlib.h>
//#include "test.h"
import "C"


//import "unsafe"

func Test() {

    log := 1 // sets logging level
    numProfiles := 3

    var profiles C._profiles

    C.initializeProfiles(&profiles, C.int(numProfiles), C.bool(true))


    profiles.profile[0].profileId = C.int(2)
    profiles.profile[0].stateFipsId = C.int(1)
    profiles.profile[0].userName.first = C.CString("test")
    profiles.profile[0].userName.last = C.CString("test")

    C.dosomething_In_C( &profiles,C.int(3))

    C.initializeProfiles(&profiles, C.int(numProfiles), C.bool(false))


    fmt.Println(int("get c variable and  return")
}

Когда я компилирую вот так profiles.profile[0].profileId = C.int(2)

Я получил сообщение об ошибке: недопустимая операция: profiles.profile[0] (тип *C.struct___6 не поддерживает индексирование)

Итак, я пробую другое решение. Перенесите массив c struct из формы c в go. так

    profile.profikes = (*[1 << 30]C._profile)(unsafe.Pointer(&profiles.profile))[:numProfiles:numProfiles]

Но получите ошибку, например, не можете использовать (*[1073741824]C.struct___6)(unsafe.Pointer(&profiles.profile))[:numProfiles:numProfiles] (введите []C.struct___6) как тип *C.struct___6 в назначении

и я боюсь, что он создаст еще один кусок памяти, когда я вызываю функцию dosomething_In_C, он не может получить данные.

Кто-нибудь знает, как это исправить?

Спасибо


person wei Zhang    schedule 16.03.2017    source источник


Ответы (1)


Вы не можете индексировать массивы C, и вы не можете назначить срез Go структуре C, но вам это не нужно, так как новый слайс ссылается на ту же область памяти.

p := (*[1 << 30]C._profile)(unsafe.Pointer(profiles.profile))[:numProfiles:numProfiles]

p[0].profileId = C.int(2)
p[0].stateFipsId = C.int(1)
p[0].userName.first = C.CString("test")
p[0].userName.last = C.CString("test")
person JimB    schedule 16.03.2017
comment
Спасибо ДжимБи. На самом деле, мне нужно сослаться на ту же память. Потому что после инициализации и присвоения значения мне нужно перейти к другой функции C в качестве параметра. Когда-то я использовал структуру C со структурой массива фиксированной длины, она поддерживала индекс. Я могу напрямую присвоить значение, например profies.profile[0].profileId = C.int(2). Но когда можно использовать массив динамической длины, это невозможно. - person wei Zhang; 16.03.2017
comment
@weiZhang: я не понимаю. Я сказал, что это действительно ссылается на одну и ту же память, и ничто не мешает вам передать указатель обратно в функцию C. Это просто позволяет вам получить доступ к значениям массива с нотацией индекса Go. - person JimB; 16.03.2017
comment
Спасибо, попробую еще раз отладить. - person wei Zhang; 16.03.2017