我想从c调用
Haskell函数,并将图像作为参数.它只是一个unsigned char数组,包含有关宽度和高度的信息(以像素为单位).
到目前为止,我有这个工作代码.
-- Stuff.hs module Stuff where import Data.List import Data.Word import qualified Data.Vector.UnBoxed as V import Foreign.Ptr import Foreign.Storable import Foreign.C.Types import Foreign.C.String import Foreign.Marshal.Array import Foreign.Marshal.Alloc foreign export ccall freeResult :: CString -> IO () foreign export ccall doWithImageStruct :: ImageStruct -> IO CString data Image = Image Word32 Word32 (V.Vector Double) type ImageStruct = Ptr ImageStructType -- CUInt is Word32. -- https://hackage.haskell.org/package/base-4.6.0.0/docs/Foreign-C-Types.html#t:CInt data ImageStructType = ImageStructType CUInt CUInt (Ptr CUChar) instance Storable ImageStructType where sizeOf _ = 12 alignment = sizeOf peek ptr = do w <- peekByteOff ptr 0 h <- peekByteOff ptr 4 p <- peekByteOff ptr 8 return (ImageStructType w h p) imageStructTypeToImage :: ImageStructType -> IO Image imageStructTypeToImage (ImageStructType (CUInt width) (CUInt height) p) = do pixelsCUChar <- peekArray (fromIntegral $width * height) p let pixels = map (\(CUChar c) -> fromIntegral c) pixelsCUChar return $Image width height (V.fromList pixels) doWithImage :: Image -> String doWithImage (Image w h p) = intercalate " " [show w,show h,show $V.sum p] doWithImageStruct :: ImageStruct -> IO CString doWithImageStruct is = do imageStruct <- peek is image <- imageStructTypeToImage imageStruct newCString $doWithImage image freeResult :: CString -> IO () freeResult s = free s
和
// StartEnd.c #include <Rts.h> void HsStart() { int argc = 1; char* argv[] = {"ghcDll",NULL}; // argv must end with NULL // Initialize Haskell runtime char** args = argv; hs_init(&argc,&args); } void HsEnd() { hs_exit(); }
它编译
ghc -Wall -O2 -outputdir build -shared -o build\Stuff.dll Stuff.hs StartEnd.c
cpp部分(MSVC 2010)看起来像这样:
// main.cpp // link with /OPT:NOREF #pragma comment(lib,"Stuff.dll.a") #include "HsFFI.h" #include "Stuff_stub.h" #include <cstdint> #include <iostream> #include <string> #include <vector> extern "C" { void HsStart(); void HsEnd(); } struct Image { Image( std::uint32_t w,std::uint32_t h,std::uint8_t* p ) : width_( w ),height_( h ),pixels_( p ) {} std::uint32_t width_; std::uint32_t height_; std::uint8_t* pixels_; }; int main() { using namespace std; HsStart(); // create image const uint32_t width = 320; const uint32_t height = 240; vector<uint8_t> mem( width * height,10 ); mem[1] = 13; Image image( width,height,&mem[0] ); // Send Image to Haskell and receive a String. auto resultPtr = doWithImageStruct( &image ); string result( reinterpret_cast<char*>( resultPtr ) ); freeResult( resultPtr ); cout << result << "\n"; HsEnd(); }
输出符合预期:
320 240 768003.0
我的问题是:这是正确的方法吗?或者只是纯粹的运气,它现在不会崩溃,实际上我有未定义的行为?