Подтвердить что ты не робот

Может ли FFI работать с массивами? Если да, то как?

Я уверен, что можно отправлять массивы через FFI, но я не могу найти примеров. Например, у меня есть массив Haskell, который я отправляю в функцию int foo(int*), или у меня есть массив C int bar[64];, который я отправляю в Haskell.

В идеале я бы хотел наиболее эффективный способ - я не хочу, чтобы было выделено кучу или ненужное копирование. Кроме того, было бы неплохо, если бы я мог использовать Haskell unboxed массивы как в Haskell, так и в C. Так какой же способ?

4b9b3361

Ответ 1

Если вы используете библиотеку Data.Vector, вы можете использовать Data.Vector.Storable для своих нужд. Затем вы можете использовать такие функции, как unsafeToForeignPtr или unsafeWith для доступа к основному иностранному указателю. Это позволяет вам вызывать C-код без какого-либо копирования или маршалинга.

Если вы хотите создать вектор из C-массива, вы можете использовать unsafeFromForeignPtr.

Для ваших примеров вы можете использовать (предполагая, что c_foo не изменяет его аргументы)

import Foreign.Ptr
import Foreign.C.Types
import System.IO.Unsafe (unsafePerformIO)
import qualified Data.Vector.Storable as SV

foreign import ccall unsafe "foo" c_foo :: Ptr CInt -> CInt

haskellFoo :: SV.Vector CInt -> CInt
haskellFoo sv = unsafePerformIO $
    SV.unsafeWith sv $ \ptr -> return (c_foo ptr)

Это можно играть в гольф:

haskellFoo sv = unsafePerformIO $
    SV.unsafeWith sv (return . c_foo)

Обратите внимание, что если ваша C-функция изменяет данные, вы не должны этого делать, вместо этого вы должны сделайте копию данных, чтобы не нарушить ссылочную прозрачность.

Если вы хотите использовать стандартный тип массива, вы можете использовать withStorableArray из Data.Array.Storable таким же образом.

Ответ 2

Спецификация FFI вполне читаема, поэтому вы можете просто сесть и проработать все это. Однако для этого конкретного вопроса вы можете перейти в раздел "Маршаллинг", в частности, Ptr и Сохраняемые подразделы, в которых описывается, что доступно для этого.

Ответ 4

Как и в C, массив в основном является указателем на первый элемент массива. Вы получаете другие элементы, делая арифметику на указателе. Ptr является членом Num, поэтому вы можете использовать обычные арифметические операции.