2015-10-21 114 views
2

我試圖讓熟悉Haskell的FFI,所以我寫了這個小例子:功能「免費」上Haskell的FFI似乎並沒有工作

Main.hs:

{-# LANGUAGE ForeignFunctionInterface #-} 

import Foreign.C.Types 
import Foreign.Ptr (Ptr) 
import Foreign.Marshal.Array (peekArray) 
import Foreign.Marshal.Alloc (free) 

foreign import ccall "test.h test" 
    test :: CInt -> Ptr CInt 

main = do 
    let rval = test 6 

    -- print the array 
    list <- peekArray 6 rval >>= return . map toInteger 
    putStrLn $ show list 

    free rval 

    -- print it again (it should okay) 
    putStrLn $ show list 

    -- try to retrieve it AGAIN after I used free. Should print random values 
    peekArray 6 rval >>= return . map toInteger >>= putStrLn . show 

測試。^h

#ifndef TEST_H 
#define TEST_H 

int* test(int a); 

#endif 

test.c的

#include "test.h" 
#include <stdio.h> 
#include <stdlib.h> 

int* test(int a) 
{ 
    int* r_val = (int*)malloc(a * sizeof(int)); 
    r_val[0] = 1; 
    r_val[1] = 2; 
    r_val[2] = 3; 
    r_val[3] = 4; 
    r_val[4] = 5; 
    r_val[5] = 6; 
    return r_val; 
} 

,當我編譯和運行Main.hs我得到的輸出是:

D:\Code\Haskell\Projects\Dev\TestFFI>cabal build 
Building TestFFI-0.1.0.0... 
Preprocessing executable 'TestFFI' for TestFFI-0.1.0.0... 
[1 of 1] Compiling Main    (src\Main.hs, dist\build\TestFFI\TestFFI-tmp\Main.o) 
Linking dist\build\TestFFI\TestFFI.exe ... 

D:\Code\Haskell\Projects\Dev\TestFFI> 
D:\Code\Haskell\Projects\Dev\TestFFI>dist\build\TestFFI\TestFFI.exe 
[1,2,3,4,5,6] 
[1,2,3,4,5,6] 
[1,2,3,4,5,6] 

似乎也沒有任何意義了我。我第三次打印陣列時,我期待着這樣的事:

[69128391783,2083719073,934857983457,98374293874,0239823947,2390847289347] 

隨機數據!

我做錯了什麼?我錯過了什麼嗎?

+0

爲什麼你認爲釋放的內存應該改變?請注意,Haskell運行時不使用malloc/free來管理內存。 – ErikR

回答

8

釋放內存後讀取內存是未定義的行爲。任何事情都是允許的 - 包括返回隨機數據,召喚鼻魔,甚至在可能的世界中,返回釋放之前存儲在內存中的數據。

+0

是的,但不應該有一個隨機的機會,這種未定義的行爲?每次運行程序時,我都會得到相同的輸出結果。如果行爲沒有定義(因爲它應該)每次都不會有不同的結果? – TheCrafter

+2

@ TheCrafter不,沒有保證。嘗試在C中做同樣的事情。'free'之後,你可能(一貫地!)看到相同的數據。或不。一切皆有可能。未定義並不意味着隨機,這意味着運行時可以做任何想要的事情。 – chi

+3

@TheCrafter:UB可能存在隨機的可能性 - 但這可能是一個非常小的機會,所以在看到它之前,您必須重新運行該程序數百萬次。或者,你可以爲投資者演示它,這幾乎可以保證最壞的情況立即顯示出來(例如計算機冒煙,而不是隨便打印垃圾)。 –