2016-01-31 14 views
5

Próbuję reprezentować Haskell par arbitralnie zagnieżdżonych w prawo (tj. Vector (Int64, (Int64, (...)))) jako 2-d tablicy w C (tj. int64_t**), indeksowane jako składnik wektora, następnie składnik krotki .Marshaling wektory wskaźników

Oto mój C Funkcja:

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"); 
    } 
} 

Na stronie Haskell mam:

{-# 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) 

Drukuje

Moduli: 10,11, 
vec 
Segmentation fault 

która prowadzi mnie do myślenia, że ​​moje wystąpienie Storable (a,b) jest w porządku : Otrzymuję wskaźnik dla (Int64,Int64), a następnie przesyłaję go do Ptr Int64 i dokładne odczytanie danych w C. Więc pytanie brzmi, co jest nie tak z wektorem? Próbuję zrobić to samo: utworzyć Vector (Int64, Int64), pobrać dla niego wskaźnik typu Ptr (Int64, Int64) i przesłać go do Ptr (Ptr Int64). Dlaczego otrzymuję segfault, gdy próbuję uzyskać dostęp do tablicy w C i jaki jest właściwy sposób gromadzenia tych danych?

+0

Przypomnijmy, że w C tablicą wskazówki mogą rozpaść na wskaźnik do int, a tablicą tablic wskazówki mogą rozpaść na wskaźnik do tablicy int, ale _nie_ do wskaźnika do wskaźnika do int. Nie można przekazać 'int a [3] [5]', gdzie oczekiwane jest 'int ** a', ale możesz tam, gdzie jest' int (* a) [5] '. – chi

Odpowiedz

4

Nie używasz tego samego formatu danych po obu stronach. Twój kod Haskella tworzy płaską tablicę wszystkich wartości we wszystkich krotkach wektora, podczas gdy twój kod C oczekuje tablicy wskaźników, po jednym dla każdego elementu wektora, wskazując wartości w tej krotce.

Jeśli można zadeklarować swoją funkcję C tak (może to jest ważne C w dzisiejszych czasach, nie wiem)

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

następnie C będzie przy użyciu tego samego układu jak Haskell. W przeciwnym razie, można wskaźnik ręcznie z

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

Niestety, składnia tablicowa nie jest dla mnie kompilacją, ale indeksowanie ręczne działa świetnie. – crockeea