2012-05-23 3 views
1

Я пытаюсь вызвать функцию в библиотеке C++ с C-совместимым заголовком, который хочет, чтобы я прошел в матрице 4x4 для ее заполнения.CGO get a [] [] float32 from C ** float

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

func GetMatrix(matrix [][]float32) 

func GetMatrix(matrix []float32) 

И заголовок с определяет это так:

void getMatrix(const float **matrix) 

Я попытался с помощью C.GoBytes, чтобы получить массив байтов, но затем оттуда я немного потерянный, поскольку я должен перейти от байтового массива к массиву указателей, который затем снова преобразую в массив байтов и, в конечном счете, массив поплавков.

По крайней мере, я думаю, что это то, что мне нужно.

Я видел примеры кода, заменяющего базовый фрагмент Go на данные массива C, но я верю в эти случаи, Go GC их не собирает. В идеале матрица [] [] float32 будет вести себя как обычный фрагмент Go.

Редактировать: документации были неправильными, и лежащие в основе типа С на самом деле массив с плавающей точкой 16 элемента.

Таким образом, возникает вопрос, могу ли я использовать C.GoBytes с указателем, указателю на массив, и если да, то как мне получить [] float32 из [] байта?

ответ

0

Я думаю, что тип Go вы должны будете использовать это

*[16]*float32 

В любом случае float32 [] [] никогда не собирается быть совместимы с ** поплавка С.

+0

Вот что я думал, но все ссылки на этот апи вызов относятся к матрице, построенной с массивом 4x4 массивов. – Gaidin

+0

Зависит от конкретного заявления C (к сожалению, не указано в вопросе). Ответ Atom, вероятно, правильный, я дам ему попробовать ;-) – zzzz

+0

Может быть, не в тему, но какой смысл иметь указатель на указатель на матрицу? – Gaidin

0

Указатель на массив 4x4 массивов имеет тип *[4]*[4]float32.

+0

Мои данные изначально были неверными, я обновил вопрос. – Gaidin

1

Edited Это печатает правильный материал

package main 

/* 
#include <stdio.h> 
void getMatrix(const float **matrix){ 
    float *m = (float *)matrix; 
    int i; 
    for(i = 0; i<9; i++) { 
     printf("%f\n",m[i]); 
    } 
} 
*/ 
import "C" 
import "unsafe" 

func main() { 
    a := []float32{1,2,3,4,5,6,7,8,9} 
    C.getMatrix((**C.float)(unsafe.Pointer(&a[0]))) 
} 
+0

Да, я пробовал это изначально, и хотя он компилируется, он фактически не получает нужные данные. Это указатель на указатель, и все это делает преобразование указателя на указатель на указатель. Проблема в том, что вы все еще нуждаетесь в этом дополнительном перенаправлении на стороне C, прежде чем сможете передать указатель на фрагмент Go. В итоге я написал небольшую функцию C, чтобы просто скопировать значения. Кажется, что он работает достаточно быстро. – Gaidin

+0

Я не уверен, что правильно вас понял. Я отредактировал свой ответ, но мне непонятно, где вам нужен байт []. – Inuart

0

Продление на ответ, предоставленной Inuart:

package main 

/* 
#include <stdio.h> 
void getMatrix(const float **matrix){ 
    float *m = (float *)*matrix; 
    int i; 
    for(i = 0; i<16; i++) { 
     printf("%f\n",m[i]); 
    } 
} 
*/ 
import "C" 

import "unsafe" 

func main() { 
    // Create the contiguous 16 element array, but organise it how it is described. 
    a := [4][4]float32{ 
     {1, 2, 3, 4}, 
     {5, 6, 7, 8}, 
     {9, 10, 11, 12}, 
     {13, 14, 15, 16}, 
    } 
    m := &a // Take the pointer. 
    C.getMatrix((**C.float)(unsafe.Pointer(&m))) // Take the handle and pass it. 
} 

Это даст вам поведение ручки, что вы, кажется, просить и имеет преимущество в том, что форма данных в Go, как представляется, запрашивается C API - нет необходимости избегать простоты использования и безопасности Go, просто потому, что вы взаимодействуете с C.

+0

Я чувствую, что это просто происходит, и это может сломаться в будущем. Причина, по которой вы вынуждены получить адрес первого элемента массива в Go (а не адрес самого массива), заключается в том, что они хотят свободы реализации для области памяти в начале массива. Единственная гарантия Go дает вам то, что элементы массива будут вместе в памяти. – Yobert

+0

Индекс не нужен, так как массив не является срезом. Хотя альтернативная реализация может нарушить этот подход, любое использование общей памяти между C и Go зависит от модели, что элементы массива смежно расположены в памяти. [This] (http://stackoverflow.com/a/15821360/1502538) ответ ничем не отличается в этом отношении и будет ломаться при тех же условиях (если не используется нестандартная реализация, которая хранит информацию в заголовке массива, а не с информацией о типе во время компиляции). BTW спецификация не гарантирует, что элементы массива смежны. – kortschak

1

Вот способ передать указатель на ход массив в функцию C, поэтому функция C может заполнить ее:

package main 
/* 
#include <stdio.h> 
void getMatrix(float *m) { 
    int i; 
    for(i = 0; i < 16; i++) { 
     m[i] = (float)i; 
    } 
} 
*/ 
import "C" 
import "fmt" 
func main() { 
    var a [16]float32 
    C.getMatrix((*C.float)(&a[0])) 
    fmt.Println(a) 
}