gpt4 book ai didi

c - haskell FFI传入和传出C结构数组

转载 作者:太空宇宙 更新时间:2023-11-04 05:52:52 25 4
gpt4 key购买 nike

我正在尝试使用 Haskell 和 Repa/DevIL 对图形文件执行一系列转换。使用的起始示例由 Haskell wiki 页面提供https://wiki.haskell.org/Numeric_Haskell:_A_Repa_Tutorial .我是一名拥有 30 年使用 erlang 经验的命令式程序员,尝试在类环境之外学习 Haskell。

问题是在文件加载首先转换为 Repa 数组后操作数据:

import Data.Array.Repa.IO.DevIL (runIL,readImage,writeImage,Image(RGB),IL)
import qualified Data.Array.Repa as R
import Data.Vector.Unboxed as DVU
import Control.Monad

main :: IO ()
main = do
[f] <- getArgs
(RGB a) <- runIL $ Data.Array.Repa.IO.DevIL.readImage f
let
c = (computeP (R.traverse a id rgbTransform)) :: IL (Array U DIM3 Float)

成功转换为类型“Array F DIM3 Float”作为 rgbTransform 的输出。从那时起,使用数据就成了一场噩梦。在 F(oreign) 和 U(nboxed) 之间切换数组存储类型会改变所有后续调用的可用性,加上 Repa 添加的 monad 层 IL 强制对第一次转换后的几乎每个方程使用 liftM:

  let -- continued
sh = liftM R.extent c -- IL DIM3
v = liftM R.toUnboxed c -- IL (Vector Float)
lv = liftM DVU.length v -- IL Int
f = liftM indexed v -- vector of tuples: (Int,a) where Int is idx
k = (Z :. 2) :. 2 :. 0 :: DIM3

这些是我可以毫无错误地调用的例程。由于 IL monad 层,如果放置在这个“let”列表中或之后,IO monad 的 print 命令不会产生任何输出。

好奇的游戏计划:

  1. 阅读图形文件(通过 Repa 完成)
  2. 调整图像大小(未完成,Repa 中没有调整大小,必须手动编码)
  3. 将图像从 Word8 转换为 Float(完成)
  4. 获取指向转换后的 Float 数据的稳定指针(未完成)
  5. 将 Float 数据就地转换为 C 结构数组{Float a,b,c;},通过 FFI 的外部 C 例程(不完全完毕)。希望这是在不编码新图形的情况下完成的通过传递指向数据的指针来数组
  6. 对转换后的数据执行更多传递以提取更多信息(部分完成)。

我正在寻求有关问题 4 和 5 的帮助。

4 -> 在尝试获取 C 可用的内存指针时,类型系统一直难以处理。翻阅堆积如山的 haskell 库调用并没有帮助。

5 -> 外部 C 例程的类型:

foreign import ccall unsafe "transform.h xform"
c_xform :: Ptr (CFloat,CFloat,CFloat) ->
CInt ->
IO ()

Ptr 应该指向一个未装箱的 rgb_t 结构平面 C 数组:

typedef struct
{
float r;
float g;
float b;
} rgb_t;

关于如何在 FFI 中处理数组指针的可用的基于 Web 的 FFI 描述如果不是完全晦涩的话也不存在。解冻并传入浮点 RGB 结构的 C 数组,就地修改它们然后卡住结果的相当简单的想法是我的想法。外部转换是纯粹的,因为相同的输入将产生可预测的输出,不使用线程,不使用全局变量,也不依赖于晦涩的库。

最佳答案

Foreign.Marshal.Array 似乎提供了一种将 haskell 数据转换为 C 数据和其他方式的方法。

我使用以下文件测试了 C 代码和 haskell 的接口(interface)(Haskell + FFI 对我来说是第一次)

hsc2hs rgb_ffi.hsc
ghc main.hs rgb_ffi.hs rgb.c

rgb.h

#ifndef RGB_H
#define RGB_H

#include <stdlib.h>

typedef struct {
float r;
float g;
float b;
} rgb_t;

void rgb_test(rgb_t * rgbs, ssize_t n);

#endif

rgb.h

#include <stdlib.h>
#include <stdio.h>
#include "rgb.h"

void rgb_test(rgb_t * rgbs, ssize_t n)
{
int i;

for(i=0; i<n; i++) {
printf("%.3f %.3f %.3f\n", rgbs[i].r, rgbs[i].g, rgbs[i].b);
rgbs[i].r *= 2.0;
rgbs[i].g *= 2.0;
rgbs[i].b *= 2.0;
}
}

rgb_ffi.hsc

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CPP #-}

module RGB where

import Foreign
import Foreign.C
import Control.Monad (ap)

#include "rgb.h"

data RGB = RGB {
r :: CFloat, g :: CFloat, b :: CFloat
} deriving Show

instance Storable RGB where
sizeOf _ = #{size rgb_t}
alignment _ = alignment (undefined :: CInt)

poke p rgb_t = do
#{poke rgb_t, r} p $ r rgb_t
#{poke rgb_t, g} p $ g rgb_t
#{poke rgb_t, b} p $ b rgb_t

peek p = return RGB
`ap` (#{peek rgb_t, r} p)
`ap` (#{peek rgb_t, g} p)
`ap` (#{peek rgb_t, b} p)

foreign import ccall "rgb.h rgb_test" crgbTest :: Ptr RGB -> CSize -> IO ();

rgbTest :: [RGB] -> IO [RGB]
rgbTest rgbs = withArray rgbs $ \ptr ->
do
crgbTest ptr (fromIntegral (length rgbs))
peekArray (length rgbs) ptr

rgbAlloc :: [RGB] -> IO (Ptr RGB)
rgbAlloc rgbs = newArray rgbs

rgbPeek :: Ptr RGB -> Int -> IO [RGB]
rgbPeek rgbs l = peekArray l rgbs

rgbTest2 :: Ptr RGB -> Int -> IO ()
rgbTest2 ptr l =
do
crgbTest ptr (fromIntegral l)
return ()

main.hs

module Main (main) where

import RGB

main =
do
let a = [RGB {r = 1.0, g = 1.0, b = 1.0},
RGB {r = 2.0, g = 2.0, b = 2.0},
RGB {r = 3.0, g = 3.0, b = 3.0}]
let l = length a
print a
-- b <- rgbTest a
-- print b

c <- rgbAlloc a
rgbTest2 c l
rgbTest2 c l
d <- rgbPeek c l
print d
return ()

关于c - haskell FFI传入和传出C结构数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35050825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com