我希望能够在非常低的层面上操作数据。
因此,我有一个函数接收虚拟内存地址作为整数,并对这个内存地址进行操作。我从C语言中接口了这个函数,所以它的类型是 (CUInt -> 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
检索它来证明指针是有效的。你可能会想要在 withForeignPtr
内部返回 Ptr
,但是文档警告不要这样做:
代码很简单:注意,从操作中返回指针并在操作完成后使用它是不安全的。所有指针的使用都应该在
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)
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')