2016-01-31 12 views
5

Ich versuche, eine Haskell vector von beliebig rechts verschachtelten Paaren (dh Vector (Int64, (Int64, (...)))) als 2-d-Array in C (dh int64_t**), zuerst indiziert als die Vektorkomponente, dann die Tupel-Komponente .Marshalling Vektoren von Zeigern

Hier ist meine C-Funktion:

void test(int64_t** y, int32_t vecSize int16_t tupSize, int64_t* tup) 
{ 
    printf("Tup vals: "); 
    for(int i = 0; i < tupSize; i++) { 
     printf("%" PRId64 ",",tup[i]); 
    } 
    printf("\n"); 


    printf("vec\n"); 
    for(int i = 0; i < vecSize; i++) { 
     printf("%d: (", i); 
     for(int j = 0; j < tupSize; j++) { 
      printf("%" PRId64 ",", y[i][j]); 
     } 
     printf(")\n"); 
    } 
} 

Auf der Haskell Seite habe ich:

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Int 
import Data.Vector.Storable (Vector, singleton, unsafeWith) 

import Foreign.Marshal.Utils (with) 
import Foreign.Ptr 
import Foreign.Storable (Storable (..)) 

foreign import ccall unsafe "test" test :: Ptr (Ptr Int64) -> Int64 -> Int16 -> Ptr Int64 -> IO() 

-- instance assumes right-nested pairs, but not enforced at type level 
instance (Storable a, Storable b) 
    => Storable (a,b) where 
    sizeOf _ = (sizeOf (undefined :: a)) + (sizeOf (undefined :: b)) 
    alignment _ = max (alignment (undefined :: a)) (alignment (undefined :: b)) 
    peek p = do 
    a <- peek (castPtr p :: Ptr a) 
    b <- peek (castPtr (plusPtr p (sizeOf a)) :: Ptr b) 
    return (a,b) 
    poke p (a,b) = do 
    poke (castPtr p :: Ptr a) a 
    poke (castPtr (plusPtr p (sizeOf a)) :: Ptr b) b 

main :: IO() 
main = do 
    let tup = (10,11) :: (Int64, Int64) 
     vec = singleton (2,3) :: Vector (Int64, Int64) 
    with tup $ \tptr -> 
    unsafeWith vec $ \vptr -> 
     test (castPtr vptr) 1 2 (castPtr tptr) 

Dieser druckt

Moduli: 10,11, 
vec 
Segmentation fault 

, die mich führt zu glauben, dass meine Storable (a,b) Instanz in Ordnung ist : Ich bekomme einen Zeiger für (Int64,Int64), dann umwandeln es Ptr Int64, und lesen Sie die Daten in C gut. So ist die Frage, was mit dem Vektor falsch läuft? Ich versuche, das gleiche zu tun: Erstellen Sie eine Vector (Int64, Int64), erhalten Sie einen Zeiger des Typs Ptr (Int64, Int64) dafür, und werfen Sie es auf eine Ptr (Ptr Int64). Warum erhalte ich einen Segmentfehler, wenn ich versuche, auf das Array in C zuzugreifen, und was ist der richtige Weg, um diese Daten zu übertragen?

+0

Recall, dass in C, ein Array von ints in einen Zeiger auf int Zerfall kann, und die ein Array von Arrays von ints kann in einen Zeiger auf Array von ints Zerfall, sondern _not_ zu einem Zeiger auf den Zeiger zu int. Sie können kein 'int a [3] [5]' übergeben, wo ein 'int ** a 'erwartet wird, aber Sie können auch ein' int (* a) [5]' angeben. – chi

Antwort

4

Sie verwenden nicht das gleiche Datenformat auf beiden Seiten. Ihr Haskell-Code erzeugt ein flaches Array aller Werte in allen Tupeln des Vektors, während Ihr C-Code ein Array von Zeigern erwartet, eines für jedes Element des Vektors, das auf die Werte in diesem Tupel zeigt.

Wenn Sie Ihre C Funktion wie folgt erklären könnte (vielleicht dies gilt C heute ist, weiß ich nicht)

void test(int64_t (*y)[tupSize], int32_t vecSize, int16_t tupSize, int64_t *tup) 

dann würde C das gleiche Layout wie Haskell verwendet werden. Sie können aber Index manuell mit

// SINGLE pointer | 
//     v 
void test(int64_t *y, int32_t vecSize, int16_t tupSize, int64_t *tup) 
... 
    printf("%" PRId64 ",", y[i*tupSize+j]); 
+0

Leider kompiliert die Point-of-Array-Syntax nicht für mich, aber die manuelle Indexierung funktioniert gut. – crockeea