Haskell如何使用c中的extern FILE *?

时间:2017-09-16 16:34:16

标签: haskell c2hs

我想从一些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);}

这是一种解决方法,但似乎并不干净。

2 个答案:

答案 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