2015-02-17 1 views
1

Я пытаюсь подключить библиотеку C++ к серверу приложений, написанному на Go. Цель состоит в том, что и библиотека C++, и сервер приложений работают над общей структурой данных, а это означает, что:Обмен данными структур (массивов) между Go (golang) и C++

  1. Сервер приложений Go может обращаться к массиву, созданному библиотекой C++.
  2. Библиотека C++ может работать с массивом, созданным сервером приложений Go.

Я играл немного с cgo и подключался к C++, и все работало до сих пор ... Однако, когда дело доходит до обмена указателями на структуры данных, я теряюсь. То, что я пытался до сих пор:

//c++ library header: xyz.h 

#include <stdlib.h> 

class CppLib { 
public: 
    CppLib(unsigned int input); 

    int * CreateArray(); 
}; 

//C++ library implementation: xyz.cpp 
#include "xyz.h" 

CppLib::CppLib(unsigned int input) { 
    _input = input; 
    } 

int * CppLib::CreateArray() { 
    int values = 5; 
    int * myPointer = new int [values]; 
    for (unsigned i = 0; i < values; ++i) { 
     myPointer[i] = i; 
    } 
    return myPointer; 
} 

Реализация интерфейса выглядит следующим образом:

//interface.h 

int * CCreateArray(); 

//interface.cc 
#include "../lib/xyz.h" 

extern "C" { 

    int * CCreateArray() { 
    CppLib lib(1); 
    return lib.CreateArray(); 
    } 
} 

Наконец реализация идти выглядит следующим образом:

package cgo_lib 

// #cgo CFLAGS: -I../lib 
// #cgo LDFLAGS: -L../lib -linterfacelib 
// #include "interface.h" 
import "C" 

func GoCreateArray() *int { 
    return *int(C.CCreateArray()) 
} 

При компиляции я получаю следующее сообщение об ошибке:

# cgo_lib 
../cgo_lib/cgo_lib.go:13: cannot convert _Cfunc_CCreateArray() (type *C.int) to type int 
../cgo_lib/cgo_lib.go:13: invalid indirect of int(_Cfunc_CCreateArray()) (type int) 

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

Большое спасибо за вашу помощь заранее.

+0

Вы не можете вернуть указатель на элемент, выделенный в стеке. Это совершенно неверно. 'CreateArray' должен специально выделить этот массив, используя' new'. – tadman

+0

Привет, tadman, спасибо за комментарий. Да, это правда ... спасибо, что указали это. Но даже при использовании нового ключевого вопроса остается вопрос, потому что ошибки все еще существуют. – Energetics

+0

Выполняет ли кастинг с '(* int) (C.CCreateArray())' лучше? Не так хорошо знакомы с Go. Я думаю, что вы непреднамеренно бросаете на «int», а затем пытаетесь отменить это так или иначе. Я также попробую пропустить явное приведение и посмотреть, сможет ли Go сделать это. – tadman

ответ

1

Это здесь:

return *int(C.CCreateArray()) 

можно записать в виде

return *((int)(C.CCreateArray())) 

Вы derreferencing int, что приводит к:

invalid indirect of int(_Cfunc_CCreateArray()) (type int) 

И в этом заявлении, отметив только эта деталь:

(int)(C.CCreateArray()) 

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

Помимо этого и проблемы с управлением памятью, которые @tadman упоминает в комментариях к вашему вопросу, Go не представляет массивы в качестве указателей на их первый элемент, как C.

Если вы хотите поделиться int S вы должны быть конкретными о ширине: в Go int имеет арку в зависимости от ширины, а также C int.

Подробнее о ОЦП: http://golang.org/cmd/cgo/

После того, как вы устранили все эти проблемы, вы будете продолжать что-то вроде этого:

s := make([]int32, 0, 0) 

h := (*reflect.SliceHeader)((unsafe.Pointer)(&s)) 

h.Data, h.Len, h.Cap = P, L, L // see below 

s = *(*[]int32)(h) 

где P является Go uintptr в массив, который вы создали в C++ и L - длина массива как Go int

+0

Привет, спасибо за ответ. Я мог бы заставить его работать точно так же, как предлагалось на вашем посту, а также в источнике, который вы связывали. Остается только вопрос: при использовании вышеописанного метода получает массив значений C.int. Было бы целесообразно преобразовать их в соответствующий goint? – Energetics

+1

Да, сделайте их типами Go, независимо от того, подписаны они или нет. Если вы этого не сделаете, вам придется «импортировать» C «весь код Go». – thwd

+1

Только две незначительные поправки: Вторая строка должна выглядеть так: 'h: = * (* reflect.SliceHeader) ((unsafe.Pointer) (& s))' - и четвертая строка должна быть - 's = * (* [] int32) (unsafe.Pointer (& ч)) ' – Energetics