Haskell如何使用c中的外部文件*?

Haskell如何使用c中的外部文件*?,haskell,c2hs,Haskell,C2hs,我想从一些c头导入一个函数,但是如何处理FILE*类型的stderr,它定义为: extern FILE* __stderrp; #define stderr __stderrp 也许不太准确。我使用c2hs进行我的外国金融机构工作,并且已经: {#pointer *FILE as File foreign finalizer fclose newtype#} 但我不能像这样导入stderr: foreign import ccall "stdio.h stderr" stderr :: F

我想从一些c头导入一个函数,但是如何处理FILE*类型的stderr,它定义为:

extern FILE* __stderrp;
#define stderr __stderrp
也许不太准确。我使用c2hs进行我的外国金融机构工作,并且已经:

{#pointer *FILE as File foreign finalizer fclose newtype#}
但我不能像这样导入stderr:

foreign import ccall "stdio.h stderr" stderr :: File
My c函数具有以下签名:

void func(FILE*);
我可以使用c2hs导入func:

{#fun func as ^ {`File'} -> `()'#}
我需要使用stderr运行func:

func(stderr);
我不熟悉外国进口机制。看来我不能用这种方式导入stderr

也许我会用一个新函数来包装我的函数

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

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

在为Haskell编写FFI代码时,需要某种“垫片”是很常见的,我建议您只编写一个帮助函数:

FILE* get_stderr() { return stderr; }
并使用它(参见本答案底部的示例)

然而,通过使用vanilla 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
//file.h
#包括
无效函数(文件*);
//文件.c
#包括“file.h”
void func(文件*f){
fputs(“输出到标准!\n”,f);
}
//File.chs
{-#语言外来功能接口#-}
模块主要在哪里
进口国外
#包括“file.h”
{#指针*文件作为文件新类型#}
{#fun func as ^{`File'}->`()'}
国外进口ccall“&stderr”stderr_ptr::ptr(ptr文件)
main::IO()
main=do stderr`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
--lib.chs
{#指针*文件作为文件新类型#}
外部导入ccall“stdio.h&u stderrp”c_stderr::Ptr(Ptr文件)--不能仅使用“stdio.h&stderr”,这可能会导致引用错误
--main.hs

斯特德:有什么问题吗?使用
foreign Import
导入它。好吧,getStderr>>=func是另一种满足我需要的解决方法,但我认为最好保留终结器,并在c函数中执行脏活。我的意思是,我不需要从c中导入stderr,因为它似乎是一个存在于链接中的变量(外部文件*u stderrp),而不仅仅是一个普通的c常量,我的意思是我不能使用类似stderr={#const stderr}
-- 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