Estoy intentando crear un contenedor Haskell para una biblioteca C. Las estructuras subyacentes son demasiado complicadas para expresarlas como tipos explícitos, y en realidad no las utilizo más que para pasar de una función C a otra, así que estoy usando EmptyDataDecls
para dejar que GHC lo resuelva.Declaración de datos vacía almacenable
Lo que necesito es un puntero a uno de estos tipos de datos, pero cuando intento crear uno con alloca
se queja de que los datos no son del tipo Storable
. Por ejemplo:
{-# 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 no se compilará esto, diciendo que no hay instancia para Storable Struct
. Yo podría aplicar a mí mismo:
instance Storable Struct where
sizeOf _ = ...
alignment _ = ...
Pero eso viene cerca de derrotar el propósito - Yo no quiero tener que definir tales cosas si no me importa lo que está en la estructura.
Me he dado cuenta de que un puntero a un puntero funciona bien, porque la clase Ptr
es Storable
. Por lo que puedo lograr lo que estoy apuntando utilizando peek
en ptr
antes de llamar get_struct
:
main = alloca $ \ptr -> do
ptr <- peek ptr
get_struct ptr
Esto se siente como un truco, sin embargo.
¿Hay alguna forma de obtener declaraciones de datos vacías que se consideren Storable
sin definir una instancia?
Esto es un truco. Nunca se asigna espacio para el puntero interno; solo estás apuntando a la memoria al azar. De esta manera yace segfaults. –
Entonces, si legítimamente quiero un puntero a un puntero, debería usar dos llamadas 'alloca' y luego' poke' un puntero al otro, ¿verdad? – zmthy
sí (o use alguna otra forma de asignación). Los usos más comunes para un puntero a un puntero son los valores de puntero, en cuyo caso la función enlazada realiza la asignación y las matrices de cadenas (pense 'argv'). Th –