У меня есть вопрос о Haskell C FFI, в частности о доступе к статическим структурам данных, экспортированным библиотекой C.
Библиотека C-библиотеки Im имеет статические структуры данных, такие как FOO_GEORGE
ниже, экспортируется следующим образом:
static struct foo_struct foo_table[] = { /* list of foo structs */ }
typedef struct foo_struct *foo_t;
foo_t FOO_GEORGE = &foo_table[0];
foo_t FOO_HARRY = &foo_table[1];
foo_t FOO_SUSAN = &foo_table[2];
/* ... */
Значение, которое мне нужно в моей библиотеке Haskell, - это адрес foo_struct
(&foo_table[n]
), то есть содержимое FOO_GEORGE
, которое помещается в непрозрачную оболочку newtype обычным способом (конструкторы не экспортируются из библиотеки, только тип):
newtype Foo = Foo { getFoo :: (Ptr Foo) }
Вот что я сейчас делаю:
foreign import ccall "&FOO_GEORGE" fooGeorgeHandle :: Ptr (Ptr Foo)
FooGeorge = Foo . unsafeDupablePerformIO . peek $ fooGeorgeHandle
Я думаю, что это подходящее использование unsafePerformIO
, так как C API и реализация говорят, что это использование peek
чистое и не имеет побочных эффектов. Кроме того, я считаю, что мне не нужно принимать какие-либо меры предосторожности, указанные в пунктах bullet в документации (начиная с {-# NOINLINE foo #-}
).
Мой общий вопрос: правильно ли я это делаю? Правильны ли биты анализа? Есть ли лучший или предпочтительный способ сделать это? Если предложение foreign import
позволило мне сделать отсрочку указателя, это было бы неплохо, но, похоже, это не так. я что-то упускаю? Можно утверждать, что это было бы плохой особенностью, так как это может быть segfault, если указатель bad — но тогда то же самое верно для peek
, которое я должен использовать вместо этого, поэтому оно приходит к одному и тому же.
Спасибо!