我想从一些c头导入一个函数,但是如何处理FILE *类型的stderr,它定义为:
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);}
这是一种解决方法,但似乎并不干净。
答案 0 :(得分:1)
要求某种" shim"这并不罕见。在为Haskell编写FFI代码时,我鼓励你只编写辅助函数:
FILE* get_stderr() { return stderr; }
并使用它(参见本答案底部的示例)。
但是,通过使用vanilla FFI对静态指针的支持,我能够得到以下最小的例子 - 它不直接导入stderr
,但导入指针< em> to 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
的好时机。
答案 1 :(得分:0)
对于版本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