2015-10-21 69 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可能存在随机的可能性 - 但这可能是一个非常小的机会,所以在看到它之前,您必须重新运行该程序数百万次。或者,你可以为投资者演示它,这几乎可以保证最坏的情况立即显示出来(例如计算机冒烟,而不是随便打印垃圾)。 –