Я хочу управлять данными по очень низкому уровню.
Поэтому у меня есть функция, которая получает адрес виртуальной памяти, поскольку целое число и "действительно наполняет" этим адресом памяти. Я соединил интерфейсом с этой функцией от C, таким образом, это имеет тип (CUInt -> a)
. Память, которую я хочу связать, является a Word8
в файле. К сожалению, я понятия не имею, как получить доступ к значению указателя к этому Word8
.
Чтобы быть ясным, мне не нужно значение Word8, мне нужно значение к адресу виртуальной памяти, который является значением указателя на него.
В качестве простого примера предположим, что вы хотите добавить смещение к указателю.
Передний вопрос:
module Main where
import Control.Monad (forM_)
import Data.Char (chr)
import Data.Word (Word8)
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (peek)
import System.IO.MMap (Mode(ReadOnly), mmapFileForeignPtr)
Да, вы написали, что вам не нужно значение Word8
, но я получил его с помощью peek
, чтобы продемонстрировать, что указатель действует. У вас может возникнуть соблазн вернуть
Ptr
изнутри withForeignPtr
, но документация предупреждает об этом:
Обратите внимание, что возвращать указатель небезопасно из действия и используйте его после завершения действия. Любое использование указателя должно быть внутри скобок
withForeignPtr
. Причина такой небезопасности та же, что и дляunsafeForeignPtrToPtr
ниже: финализатор может работать раньше, чем ожидалось, потому что компилятор может отслеживать использование только объектаForeignPtr
, но неИз него сделан объект Ptr
.
Код прост:
doStuff :: ForeignPtr Word8 -> Int -> IO ()
doStuff fp i =
withForeignPtr fp $ \p -> do
let addr = p `plusPtr` i
val <- peek addr :: IO Word8
print (addr, val, chr $ fromIntegral val)
Чтобы приблизиться к « Word8
в файле» из вашего вопроса, основная память программы отображает файл и использует этот буфер для работы с адресами памяти.
main :: IO ()
main = do
(p,offset,size) <- mmapFileForeignPtr path mode range
forM_ [0 .. size-1] $ \i -> do
doStuff p (offset + i)
where
path = "/tmp/input.dat"
mode = ReadOnly
range = Nothing
-- range = Just (4,3)
Вывод:
(0x00007f1b40edd000,71,'G') (0x00007f1b40edd001,117,'u') (0x00007f1b40edd002,116,'t') (0x00007f1b40edd003,101,'e') (0x00007f1b40edd004,110,'n') (0x00007f1b40edd005,32,' ') (0x00007f1b40edd006,77,'M') (0x00007f1b40edd007,111,'o') (0x00007f1b40edd008,114,'r') (0x00007f1b40edd009,103,'g') (0x00007f1b40edd00a,101,'e') (0x00007f1b40edd00b,110,'n') (0x00007f1b40edd00c,33,'!') (0x00007f1b40edd00d,10,'\n')
Вы, вероятно, ищете ptrToIntPtr и, возможно, fromIntegral , чтобы сделать его CUInt.
Обратите внимание, что CUInt не может представлять указатель на всех платформах.