2010-03-05 12 views
9

Deseo manipular datos en un nivel muy bajo.¿Cómo obtener un valor de puntero en Haskell?

Por lo tanto, tengo una función que recibe una dirección de memoria virtual como un entero y "hace cosas" con esta dirección de memoria. Interfacé esta función desde C, por lo que tiene el tipo (CUInt -> a). La memoria que quiero vincular es Word8 en un archivo. Lamentablemente, no tengo idea de cómo acceder al valor del puntero a ese Word8.

Para ser claros, no necesito el valor de Word8, necesito el valor de la dirección de la memoria virtual, que es el valor del puntero al mismo.

+0

¿No puedes hacer una función en C para eliminar la referencia al puntero? – kennytm

Respuesta

6

Por un simple ejemplo, digamos que desea agregar un desplazamiento al puntero.

Información preliminar:

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) 

Sí, se escribió que no desea que el valor de la Word8, pero he recuperado con peek para demostrar que el puntero es válido. Usted puede verse tentado a return la PtrwithForeignPtr desde el interior, pero la documentación que advierte contra:

en cuenta que no es seguro regresar el puntero de la acción y utilizarlo después de la acción completa. Todos los usos del puntero deben estar dentro del soporte withForeignPtr. La razón de esta inseguridad es la misma que para unsafeForeignPtrToPtr a continuación: el finalizador puede ejecutarse antes de lo esperado, porque el compilador solo puede rastrear el uso del objeto ForeignPtr, no un objeto Ptr hecho a partir de él.

El código es sencillo:

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) 

para aproximar “un Word8 en un archivo” de su pregunta, el programa principal mapea en memoria un archivo y utiliza ese búfer hacer cosas con las direcciones de memoria.

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) 

Salida:

(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

Probablemente esté buscando ptrToIntPtr y probablemente fromIntegral para que sea un CORRECTO.

Tenga en cuenta que un CUInt no puede representar un puntero en todas las plataformas.

Cuestiones relacionadas