如何在Haskell中获取指针值?

11

我希望能够在非常低的层面上操作数据。

因此,我有一个函数接收虚拟内存地址作为整数,并对这个内存地址进行操作。我从C语言中接口了这个函数,所以它的类型是 (CUInt -> a)。 我想要链接的内存是文件中的一个 Word8。不幸的是,我不知道如何访问指向那个 Word8 的指针值。

明确一点,我不需要 Word8 的值,我需要虚拟内存地址的值,也就是指向它的指针的值。


你不能在C语言中创建一个解引用指针的函数吗? - kennytm
2个回答

7
为了举一个简单的例子,假设您想要在指针中添加一个偏移量。
前言:
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)

为了实现你所提到的“文件中的Word8”(在IT技术中),主程序会映射一个文件并使用该缓冲区来处理内存地址。
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
您可能正在寻找ptrToIntPtrfromIntegral,以将其转换为CUInt。请注意,不是所有平台都支持CUInt表示指针。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接