문제

I try to work with this simple C-code from Haskell:

time_t rawTime = time( NULL );
struct tm* timeInfo = localtime( &rawTime );  /* Using address of a local variable */
printf( "The current date is: %s", asctime( timeInfo ) );

So I write:

data CTmStruct = CTmStruct
type CTmStructPtr = Ptr CTmStruct

foreign import ccall "time"      c_time      :: Ptr CTime    -> IO CTime
foreign import ccall "localtime" c_localtime :: Ptr CTime    -> IO CTmStructPtr
foreign import ccall "asctime"   c_asctime   :: CTmStructPtr -> CString

main :: IO ()
main = do
    rawTime <- c_time nullPtr
    tmStructPtr <- c_localtime ???  -- How to get an address of rawTime?
    print $ c_asctime tmStructPtr

So how can I get an address of a local value rawTime for putting it as an argument of a c_localtime function? I've read documentation to Foreign module, but I didn't find answer for this question. I'd be very grateful for any help.

도움이 되었습니까?

해결책

I was able to do:

import Foreign.C.String
import Foreign.Marshal.Alloc

-- Your declarations and foreign bindings here

getTime :: IO String
getTime = do
    p <- malloc
    c_time p
    tmPtr <- c_localtime p
    str <- peekCString $ c_asctime tmPtr
    free p
    return str

main :: IO ()
main = do
    currentTime <- getTime
    putStrLn currentTime

The key is using malloc and free, you explicitly allocate the space, pass it to c_time to set the contents, then c_localtime to format it as a CTmStruct, then pass that to c_asctime to convert to a CString, marshal back to a Haskell String with peekCString, and finally free the pointer used to get the time.


I guess I should have realized this sooner, but a better solution would be to use alloca:

getTime :: IO String
getTime = alloca $ \p -> do
    c_time p
    tm <- c_localtime p
    peekCString $ c_astime tm

Which is safer, shorter, and easier. The alloca function does the allocation and freeing of the pointer for you, all you have to do is use it.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top