Storable empty data declaration

2019-03-26 08:13发布

问题:

I'm attempting to create a Haskell wrapper for a C library. The underlying structs are too complicated to express as explicit types, and I don't actually use them other than for passing between C functions, so I'm using EmptyDataDecls to let GHC work it out for me.

What I need is a pointer to one of these data types, but when I attempt to create one with alloca it complains that the data is not of the type Storable. For example:

{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}

module Main where

import Foreign.Marshal.Alloc
import Foreign.Ptr

data Struct

foreign import ccall "header.h get_struct"
    get_struct :: Ptr Struct -> IO ()

main = alloca $ \ptr -> get_struct ptr

GHC won't compile this, saying there's no instance for Storable Struct. I could implement it myself:

instance Storable Struct where
    sizeOf _    = ...
    alignment _ = ...

But that comes close to defeating the purpose - I don't want to have to define such things if I don't care what's in the struct.

I've noticed that a pointer to a pointer works fine, because the Ptr class is Storable. So I can accomplish what I'm aiming for by using peek on ptr before calling get_struct:

main = alloca $ \ptr -> do
  ptr <- peek ptr
  get_struct ptr

This feels like a hack, though.

Is there a way to get empty data declarations to be considered Storable without defining an instance?

回答1:

You can't allocate something if you don't know how big it is. Is the function just going to ignore its argument? Then pass in a null pointer. Otherwise, you need to actually allocate enough space for the struct - don't cut corners by allocating a zero-byte or pointer-sized buffer, as then the called function will write past the end of your buffer, corrupting memory.

Either finish the data declaration, or write a Storable instance with proper size and alignment values; there's no way around providing size/alignment data in some form.



回答2:

Here's another approach that might work for you. I assume that you have access to all of the C header files that define the objects you need to allocate. If that's true, you could write a thin layer of C code for allocating and freeing the C objects. Your Haskell code can then call these C functions without the Haskell code ever needing to know what's behind the pointers. Haskell can also automatically call the free code when Haskell's garbage collector knows that the objects are no longer needed.



标签: haskell ghc ffi