Союз и тип ** с FFI в Haskell? - PullRequest
2 голосов
/ 30 июня 2011

Мне нужно знать, как я могу разрешить Союзы и Тип ** (например, int **) с FFI?Я знаю, что мне нужен экземпляр Storable для структур, могу ли я использовать его и для союзов?

объединение, подобное этому:

typedef union {
     int i;
     char c;
} my_union;

Это обычно представляется в Haskell как:

data MyUnion = I CInt | C CChar

Мой вопрос: как бы вы собрали (определите сохраняемый экземпляр) myUnion в my_union?Насколько я понимаю, экземпляр my_union будет занимать размер байтов (int) в памяти, то есть размер его самого большого члена.Таким образом, чтобы сохранить это, мы напишем что-то вроде:

instance Storable myUnion where
     size _ = #{size my_union} -- <-- hsc2hs shortcut
     alignment _ = alignment undefined::CInt -- <-- What should this really be?
     peek ptr = do -- <-- How are you supposed to know which element to extract?
     poke ptr (I i) =  poke ptr i -- <-- Or should this be #{poke my_union, i} ptr i ?
     poke ptr (C c) = poke ptr c

Кроме того, как вы можете представить int** с FFI?когда я получил функцию типа int foo(int i1, int* i2);, подпись была бы: foo -> CInt -> Ptr CInt -> CInt

но что, если есть : int foo(int i1, int** i2);

Ответы [ 3 ]

5 голосов
/ 30 июня 2011

Даже в C вы не знали бы, какой член использовать (если это не ясно из контекста), если вам вручили:.

typedef struct {
     int type;
     union {
          int i;
          char c;
     } my_union;
} my_tagged_union;
2 голосов
/ 30 июня 2011

C союзы не помечены как союзы, см. википедию на этом . В haskell MyUnion будет занимать больше памяти, чем один необработанный (без упаковки) 64-битный int. В GHC это был бы специальный указатель на thunk или значение: thunk - это когда ленивый MyUnion еще не был оценен, значение для того, когда он был оценен, а размер памяти, на который указывают, может варьироваться (в отличие от объединений в с). «Специальный» указатель будет использовать обычно нулевые младшие биты 64-разрядного указателя, чтобы указать, известно ли это как значение C или I, чтобы объединить тегирование с указателем.

Менее ленивое объявление в Haskell можно сделать с помощью

data MyUnion1 = I !Int | C !Char
data MyUnion2 = I {-# UNPACK #-} !Int | C {-# UNPACK #-} !Char

Где "!" указывает, что значение никогда не сохраняется как неоцененный раздел. Комментарий к прагме компилятора UNPACK просит GHC хранить необработанное распакованное значение рядом с тегом вместо хранения указателя на Int или Char. Таким образом, MyUnion2 может занимать меньше памяти и будет строгим, а не ленивым.

Кроме того, я должен подчеркнуть, что "char" из C - это один байт со знаком, в то время как "Char" в Haskell - это полная кодовая точка Unicode (значение от 0 до 1114111). Чтобы хранить символ C "в Haskell, вы должны использовать CChar .

У вас есть союзы, используемые в C, и вам нужно их сериализовать и десериализовать? У вас уже есть двоичный формат, используемый C? Если вам нужно изобрести бинарный формат, вам нужно разработать тег, чтобы сделать Haskell счастливым. В вашем примере на C нет способа определить, было ли значение «создано» с помощью int или char, в то время как MyUnion в Haskell может определить, было ли значение создано с помощью I или C.

Тип C, который вы написали, также довольно опасен, как будто я пишу в однобайтовый "char" и читаю многобайтовый "int", остальные байты в "int", вероятно, не определены.

0 голосов
/ 01 июля 2011

Вы можете легко получить указатели на указатель (я использую нечто подобное для передачи параметра (void*)&val в библиотеку C).На ghci:

> a <- malloc :: (IO (Ptr Int))
> dir_a <- malloc :: (IO (Ptr (Ptr Int)))
> poke dir_a a
> poke a 5

> b <- peek dir_a
> peek b
5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...