2010-03-05 5 views
9

매우 낮은 수준의 데이터를 조작하고 싶습니다.하스켈에서 포인터 값을 얻는 방법?

따라서 가상 메모리 주소를 정수로 받고이 메모리 주소로 "처리"하는 기능이 있습니다. 이 함수는 C에서 인터페이스되었으므로 유형은 (CUInt -> a)입니다. 링크하려는 메모리가 파일에 Word8입니다. 슬프게도, 나는 그 포인터 값을 Word8에 액세스하는 방법을 모른다.

분명히하려면 Word8의 값이 필요하지 않습니다. 가상 메모리 주소의 값이 필요합니다. 포인터의 값입니다.

+0

당신이 포인터 역 참조로 C에서 함수를 만들 수 있습니까? – kennytm

답변

6

간단한 예제를 위해 포인터에 오프셋을 추가하려고한다고 가정 해보십시오.

서문 :

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로를 검색했습니다. 당신은 returnwithForeignPtr 내부에서 Ptr에 유혹 될 수 있지만 내용은 해당에 대해 경고 :이 작업에서 포인터를 반환하고 작업이 완료된 후 사용하는 것이 안전하지

하는 것으로. 포인터의 모든 용도는 withForeignPtr 대괄호 안에 있어야합니다. 컴파일러는 개체가 아니라 ForeignPtr 개체의 사용을 추적 할 수 있기 때문에 finalizer는 예상보다 빨리 실행될 수 있습니다.

코드는 간단하다 :

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

ptrToIntPtr과 아마도 fromIntegral을 찾고있을 것입니다.

CUInt는 모든 플랫폼에서 포인터를 나타낼 수 없다는 점에 유의하십시오.