2012-05-23 88 views
1

我試圖在C++庫中調用一個C兼容頭文件的函數,該頭文件需要我傳入一個4x4矩陣來填充它。CGO從C **獲取[] [] float32 float **

我轉到函數定義是這樣的:

func GetMatrix(matrix [][]float32) 

func GetMatrix(matrix []float32) 

以及C頭文件定義它是這樣的:

void getMatrix(const float **matrix) 

我已經嘗試使用C.GoBytes獲得一個字節數組,但從那裏我是一個因爲我必須從一個字節數組轉換爲一個指針數組,所以我再次轉換爲一個字節數組,最後是一個浮點數組。

至少我認爲這就是我需要做的。

我見過代碼用C數組數據替換底層Go slice的代碼示例,但我相信在這些情況下,Go GC不會收集它們。理想情況下,matrix [] [] float32的行爲就像普通的Go切片一樣。

編輯: 文檔是不正確的,並且底層的C型實際上是一個16族元素float數組。

因此,問題就變成了,我可以使用C.GoBytes和一個指針,指向一個數組的指針,如果是的話,如何從[]字節獲得[] float32?

回答

0

我認爲你將不得不使用Go類型是

*[16]*float32 

在任何情況下,[] [] FLOAT32永遠不會與**浮動C.

+0

這就是我想,但這個API調用的所有參考內置矩陣與一個4x4數組陣列。 – Gaidin

+0

取決於C的具體聲明(不幸未在問題中顯示)。 Atom的答案可能是正確的,我會試試看;-) – zzzz

+0

也許是關於主題,但是有一個指向矩陣指針的指針呢? – Gaidin

0

兼容指向4x4陣列陣列的指針的類型爲*[4]*[4]float32

+0

我的信息最初是不正確的,我更新了這個問題。 – Gaidin

1

編輯將打印出正確的東西

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之間共享內存的任何使用都取決於數組元素在內存中連續排列的模型。 [這](http://stackoverflow.com/a/15821360/1502538)答案在這方面沒有什麼不同,並會在相同的條件下破壞(除非使用非理智的實現將存儲的信息存儲在數組頭中而不是處理在編譯時輸入類型信息)。順便說一句,規範並不保證數組元素是相鄰的。 – 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) 
}