Transfer image from C ++ to Haskell and get the string back

I want to call a Haskell function from C ++ with the image as a parameter. It's just an unsigned char array with width and height information in pixels.

I still have this working code.

-- 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 whp) 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 whp) = 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 

and

 // 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(); } 

It compiles with

 ghc -Wall -O2 -outputdir build -shared -o build\Stuff.dll Stuff.hs StartEnd.c 

The cpp part (MSVC 2010) is as follows:

 // 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(); } 

The output will be as expected:

 320 240 768003.0 

My question is: is this the right way to do this? Or is it just luck that it is not crashing right now, and in fact I have undefined behavior?

Edit: I fixed the code above to show the correct use of integers of a fixed bit length for future readers of this stream.

+7
c ++ arrays pointers haskell ffi
source share
1 answer

I suggest you use C-> Hs to generate an instance of Storable ImageStructType . Everything else looks good.

+2
source share

All Articles