How to get a pointer value in Haskell?
I wish to manipulate data on a very low level.
Therefore I have a function that receives a virtual memory address as an integer and "does stuff" with this memory address. I interfaced this function from C, so it has the type (CUInt -> a)
.
The memory I want to link is a Word8
in a file. Sadly, I have no idea how to access the pointer value to that Word8
.
To be clear, I do not need the value of the Word8, i need the value to the virtual memory address, which is 开发者_JS百科the value of the pointer to it.
For the sake of a simple example, say you want to add an offset to the pointer.
Front matter:
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)
Yes, you wrote that you don't want the value of the Word8
, but I've retrieved it with peek
to demonstrate that the pointer is valid. You might be tempted to return
the Ptr
from inside withForeignPtr
, but the documentation warns against that:
Note that it is not safe to return the pointer from the action and use it after the action completes. All uses of the pointer should be inside the
withForeignPtr
bracket. The reason for this unsafeness is the same as forunsafeForeignPtrToPtr
below: the finalizer may run earlier than expected, because the compiler can only track usage of theForeignPtr
object, not aPtr
object made from it.
The code is straightforward:
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)
To approximate “a Word8
in a File” from your question, the main program memory-maps a file and uses that buffer to do stuff with memory addresses.
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)
Output:
(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')
You are probably looking for ptrToIntPtr and probably fromIntegral to make it a CUInt.
Note that a CUInt cannot represent a pointer on all platforms, though.
精彩评论