如果一个C / C ++头文件中有一个常量值,那么人们想要将它带入Haskell项目:
static const char * Name = "Name_001";
如何使用Haskell的FFI功能实现这一目标?
答案 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