Как получить значение указателя в Haskell? - PullRequest
11 голосов
/ 05 марта 2010

Я хочу манипулировать данными на очень низком уровне.

Поэтому у меня есть функция, которая получает адрес виртуальной памяти в виде целого числа и «делает вещи» по этому адресу памяти.Я связал эту функцию с C, поэтому она имеет тип (CUInt -> a).Память, которую я хочу связать, - это Word8 в файле.К сожалению, я понятия не имею, как получить доступ к значению указателя на Word8.

Чтобы было ясно, мне не нужно значение Word8, мне нужно значение адреса виртуальной памяти, которое является значением указателя на него.

Ответы [ 2 ]

7 голосов
/ 05 марта 2010

Ради простого примера, скажем, вы хотите добавить смещение к указателю.

Фасад:

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, чтобы продемонстрировать, что указатель действителен. У вас может возникнуть соблазн return 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')
3 голосов
/ 05 марта 2010

Вы, вероятно, ищете ptrToIntPtr и, вероятно, из Integral , чтобы сделать его CUInt.

Обратите внимание, что CUInt не может представлять указатель на всех платформах.

...