指针的编组矢量

时间:2016-01-31 16:26:35

标签: haskell ffi

我试图将任意右嵌套对(即Vector (Int64, (Int64, (...))))的Haskell vector表示为C中的2-d数组(即int64_t**),首先索引为向量组件,然后是元组组件。

这是我的C函数:

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

在Haskell方面,我有:

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

打印

Moduli: 10,11,
vec
Segmentation fault

这让我认为我的Storable (a,b)实例很好:我正在获取(Int64,Int64)的指针,然后将其转换为Ptr Int64,并在C中读取数据就好了那么问题是向量出了什么问题?我正在尝试做同样的事情:创建一个Vector (Int64, Int64),为它获取一个类型为Ptr (Int64, Int64)的指针,并将其转换为Ptr (Ptr Int64)。当我尝试在C中访问数组时,为什么会出现段错误,以及编组这些数据的正确方法是什么?

1 个答案:

答案 0 :(得分:4)

您并未在双方使用相同的数据格式。你的Haskell代码在向量的所有元组中生成一个包含所有值的平面数组,而你的C代码需要一个指针数组,一个用于向量的每个元素,指向其中的值元组。

如果你可以像这样声明你的C函数(现在这可能是有效的C,我也不知道)

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

然后C将使用与Haskell相同的布局。否则,您可以使用

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