0

我想从一些 c 头文件中导入一个函数,但是如何处理 FILE* 类型的标准错误,它定义为:

extern FILE* __stderrp;
#define stderr __stderrp

也许不准确。我将 c2hs 用于我的 ffi 工作,并且已经拥有:

{#pointer *FILE as File foreign finalizer fclose newtype#}

但我不能像这样导入标准错误:

foreign import ccall "stdio.h stderr" stderr :: File

我的 c 函数具有签名:

void func(FILE*);

我可以用 c2hs 导入 func:

{#fun func as ^ {`File'} -> `()'#}

我需要使用 stderr 来运行 func:

func(stderr);

我对外国进口机制不熟悉。看来我不能以这种方式导入stderr。

附言。也许我会将我的函数包装在一个新函数中

void func2(void){func(stderr);}

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

4

2 回答 2

1

在为 Haskell 编写 FFI 代码时,需要某种“垫片”并不罕见,我鼓励您只编写一个辅助函数:

FILE* get_stderr() { return stderr; }

并使用它(请参阅此答案底部的示例)。

但是,通过使用 vanilla FFI 对静态指针的支持,我能够使以下最小示例正常工作——它不stderr直接导入,而是导入指向指针的指针stderr。这种导入是c2hs不直接支持的,所以接口代码很丑,而且我认为没有什么办法可以避免stderr在IO monad中取指针值,不管你有没有用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您的好时机。

于 2017-09-16T19:16:07.980 回答
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
于 2017-09-17T03:43:39.970 回答