Haskell 如何使用来自 c 的 extern FILE*?
Haskell how to work with extern FILE* from c?
我想从一些 c 头文件中导入一个函数,但是如何处理定义为 FILE* 类型的标准错误:
extern FILE* __stderrp;
#define stderr __stderrp
也许不准确。我将 c2hs 用于我的 ffi 工作,并且已经拥有:
{#pointer *FILE as File foreign finalizer fclose newtype#}
但我不能像这样导入 stderr:
foreign import ccall "stdio.h stderr" stderr :: File
我的 c 函数具有签名:
void func(FILE*);
我可以用 c2hs 导入 func:
{#fun func as ^ {`File'} -> `()'#}
我需要使用 stderr 来 运行 func:
func(stderr);
我对外国进口机制一窍不通。看来我不能用这种方式导入stderr。
ps。也许我会把我的函数包装在一个新函数中
void func2(void){func(stderr);}
这是一种解决方法,但似乎不够干净。
在为 Haskell 编写 FFI 代码时需要某种 "shim" 的情况并不少见,我鼓励您只编写一个辅助函数:
FILE* get_stderr() { return stderr; }
并使用它(参见本答案底部的示例)。
但是,通过使用普通 FFI 对静态指针的支持,我能够让下面的最小示例工作——它不直接导入 stderr
,而是导入一个指针 到 stderr
指针。 c2hs 不直接支持这种导入,所以接口代码很难看,而且我不认为有任何方法可以避免在 IO monad 中获取 stderr
指针值,无论是否独立你用c2hs.
// file.h
#include <stdio.h>
void func(FILE*);
// file.c
#include "file.h"
void func(FILE *f) {
fputs("Output to stderr!\n", f);
}
// File.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign
#include "file.h"
{#pointer *FILE as File newtype#}
{#fun func as ^ { `File' } -> `()'#}
foreign import ccall "&stderr" stderr_ptr :: Ptr (Ptr File)
main :: IO ()
main = do stderr <- File <$> peek stderr_ptr
func stderr
相比之下,这个带有辅助函数的最小示例在 Haskell 级别看起来更清晰:
// file.h
#include <stdio.h>
void func(FILE*);
FILE* get_stderr(void);
// file.c
#include "file.h"
void func(FILE *f) {
fputs("Output to stderr!\n", f);
}
FILE* get_stderr(void) {return stderr; }
// File.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
#include "file.h"
{#pointer *FILE as File newtype#}
{#fun func as ^ { `File' } -> `()'#}
{#fun pure get_stderr as ^ {} -> `File'#}
main :: IO ()
main = func getStderr
请注意,在这两个示例中,我删除了您的 fclose
终结器。您可能不希望 Haskell 武断地决定现在是关闭 stderr
的好时机。
使用 0.28.2 版本的 c2hs,以下代码有效:
-- lib.chs
{#pointer *FILE as File newtype#}
foreign import ccall "stdio.h &__stderrp" c_stderr :: Ptr (Ptr File) -- can not just use "stdio.h &stderr", this may cause a reference error
-- main.hs
stderr <- File <$> peek c_stderr
func stderr
我想从一些 c 头文件中导入一个函数,但是如何处理定义为 FILE* 类型的标准错误:
extern FILE* __stderrp;
#define stderr __stderrp
也许不准确。我将 c2hs 用于我的 ffi 工作,并且已经拥有:
{#pointer *FILE as File foreign finalizer fclose newtype#}
但我不能像这样导入 stderr:
foreign import ccall "stdio.h stderr" stderr :: File
我的 c 函数具有签名:
void func(FILE*);
我可以用 c2hs 导入 func:
{#fun func as ^ {`File'} -> `()'#}
我需要使用 stderr 来 运行 func:
func(stderr);
我对外国进口机制一窍不通。看来我不能用这种方式导入stderr。
ps。也许我会把我的函数包装在一个新函数中
void func2(void){func(stderr);}
这是一种解决方法,但似乎不够干净。
在为 Haskell 编写 FFI 代码时需要某种 "shim" 的情况并不少见,我鼓励您只编写一个辅助函数:
FILE* get_stderr() { return stderr; }
并使用它(参见本答案底部的示例)。
但是,通过使用普通 FFI 对静态指针的支持,我能够让下面的最小示例工作——它不直接导入 stderr
,而是导入一个指针 到 stderr
指针。 c2hs 不直接支持这种导入,所以接口代码很难看,而且我不认为有任何方法可以避免在 IO monad 中获取 stderr
指针值,无论是否独立你用c2hs.
// file.h
#include <stdio.h>
void func(FILE*);
// file.c
#include "file.h"
void func(FILE *f) {
fputs("Output to stderr!\n", f);
}
// File.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign
#include "file.h"
{#pointer *FILE as File newtype#}
{#fun func as ^ { `File' } -> `()'#}
foreign import ccall "&stderr" stderr_ptr :: Ptr (Ptr File)
main :: IO ()
main = do stderr <- File <$> peek stderr_ptr
func stderr
相比之下,这个带有辅助函数的最小示例在 Haskell 级别看起来更清晰:
// file.h
#include <stdio.h>
void func(FILE*);
FILE* get_stderr(void);
// file.c
#include "file.h"
void func(FILE *f) {
fputs("Output to stderr!\n", f);
}
FILE* get_stderr(void) {return stderr; }
// File.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
#include "file.h"
{#pointer *FILE as File newtype#}
{#fun func as ^ { `File' } -> `()'#}
{#fun pure get_stderr as ^ {} -> `File'#}
main :: IO ()
main = func getStderr
请注意,在这两个示例中,我删除了您的 fclose
终结器。您可能不希望 Haskell 武断地决定现在是关闭 stderr
的好时机。
使用 0.28.2 版本的 c2hs,以下代码有效:
-- lib.chs
{#pointer *FILE as File newtype#}
foreign import ccall "stdio.h &__stderrp" c_stderr :: Ptr (Ptr File) -- can not just use "stdio.h &stderr", this may cause a reference error
-- main.hs
stderr <- File <$> peek c_stderr
func stderr