将FFI常量引入Haskell项目

时间:2017-09-04 03:32:59

标签: haskell ffi

如果一个C / C ++头文件中有一个常量值,那么人们想要将它带入Haskell项目:

static const char * Name = "Name_001";

如何使用Haskell的FFI功能实现这一目标?

1 个答案:

答案 0 :(得分:2)

正如@melpomene指出的那样,static变量不能用于FFI。包含此头文件的每个翻译单元都将创建自己的静态变量的非导出副本。不出所料,这意味着Name甚至不会出现在编译的目标文件中。

$ cat c_file.c
static const char * Name = "Name_001";
$ gcc -O -c c_file.c
$ objdump c_file.o

c_file.o: file format Mach-O 64-bit x86-64

SYMBOL TABLE:
$

将此与非静态Name变量进行比较:

$ cat c_file.c
const char * Name = "Name_001";
$ gcc -O -c c_file.c
$ objdump c_file.o

c_file.o: file format Mach-O 64-bit x86-64

SYMBOL TABLE:
0000000000000010 g       __DATA,__data  _Name
$

毋庸置疑,您需要在符号表中使用Name才能在Haskell的FFI中导入。采用第二种变体,导入Name变得非常简单:

{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign.Storable
import Foreign.C.String
import Foreign.Ptr

foreign import ccall "&Name" c_Name :: Ptr CString

name :: IO String
name = peek c_Name >>= peekCString

main :: IO ()
main = do
  n <- name
  putStrLn ("Name: " ++ n)

如果你想让我确信Name实际上是一个常量字符串,you probably need char const * const = "Name_001;。然后,随意在name

的定义中抛出unsafeDupablePerformIO
{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign.Storable
import Foreign.C.String
import Foreign.Ptr

import System.IO.Unsafe

foreign import ccall "&Name" c_Name :: Ptr CString

name :: String
name = unsafeDupablePerformIO (peek c_Name >>= peekCString)

main :: IO ()
main = putStrLn ("Name: " ++ name)

在任何一种情况下,您都会获得预期的输出:

$ gcc -O -c c_file.c
$ ghc -O2 -Wall main.hs c_file.o
[1 of 1] Compiling Main             ( main.hs, main.o )
Linking main ...
$ ./main
Name: Name_001