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?
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