Хранилище пустое объявление данных
Вопрос
Я пытаюсь создать обертку Haskell для библиотеки C. Базовые структуры слишком сложны, чтобы выразить как явные типы, и я на самом деле не использую их, кроме прохождения между функциями C, поэтому я использую EmptyDataDecls
Чтобы GHC разрабатывал это для меня.
Что мне нужно, так это указатель на один из этих типов данных, но когда я пытаюсь создать один с alloca
он жалуется, что данные не имеют типа Storable
. Анкет Например:
{-# 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 не скомпилирует это, сказав, что нет экземпляра для Storable Struct
. Анкет Я мог бы реализовать это сам:
instance Storable Struct where
sizeOf _ = ...
alignment _ = ...
Но это приближается к победе над целью - я не хочу определять такие вещи, если мне все равно, что в структуре.
Я заметил, что указатель на указатель работает нормально, потому что Ptr
Класс Storable
. Анкет Так что я могу выполнить то, к чему я стремлюсь peek
на ptr
перед звонком get_struct
:
main = alloca $ \ptr -> do
ptr <- peek ptr
get_struct ptr
Это похоже на взлом.
Есть ли способ получить пустые объявления данных Storable
без определения экземпляра?
Решение
Вы не можете что -то выделить, если не знаете, насколько это велика. Собирается ли функция игнорировать свой аргумент? Затем пройдите в нулевом указателе. В противном случае, вам нужно на самом деле выделить достаточно места для структуры-не вырезать углы, выделяя буфер с нулевым или размером с указатель, так как тогда вызывающаяся функция будет писать после конца вашего буфера, повреждающего память.
Либо заканчивайте объявление данных, либо напишите художественный экземпляр с правильным размером и значениями выравнивания; В той или иной форме нет способа предоставить данные о размерах/выравнивании.
Другие советы
Вот еще один подход, который может сработать для вас. Я предполагаю, что у вас есть доступ ко всем файлам заголовка C, которые определяют объекты, необходимые для распределения. Если это правда, вы можете написать тонкий слой C -кода для распределения и освобождения объектов C. Ваш код Haskell может затем вызвать эти C -функции без кода Haskell, когда -либо не нужно знать, что стоит за указателями. Haskell также может автоматически вызвать бесплатный код, когда коллекционер мусора Haskell знает, что объекты больше не нужны.