我有一个使用C99 bool
数据类型的库,我想通过FFI调用它。
在Haskell中,C99 bool的对应类型是什么?在Foreign.C.types中有CInt、CShort等类型,但没有CBool。
如果没有“正确”的bool
类型,有哪种安全的替代类型可以传递给期望bool
的函数?
另一种方法是修改C库,但我想保持其完整性。
我有一个使用C99 bool
数据类型的库,我想通过FFI调用它。
在Haskell中,C99 bool的对应类型是什么?在Foreign.C.types中有CInt、CShort等类型,但没有CBool。
如果没有“正确”的bool
类型,有哪种安全的替代类型可以传递给期望bool
的函数?
另一种方法是修改C库,但我想保持其完整性。
由于C99中sizeof(_Bool)
的大小是实现定义的(参见ISO / IEC 9899:1999 6.2.5、6.2.6和6.5.3.4/4), 明显的可移植解决方案是通过使用int
而不是bool
调用这些函数的包装器。或者,如果您不关心可移植性,可以检查您的编译器文档以找出您平台上的_Bool
大小,并使用相应的FFI类型。
我猜CBool
在Foreign.C.Types
中不存在的原因是底层的C实现不支持C99的所有特性。一个非常广泛使用的编译器(MSVC)根本不支持C99。
CBool
,在这种情况下,您假定存在符合标准的编译器。我认为更可能的原因是CBool
更加晦涩和不常用,因此还没有人发现有必要编写支持。 - Ben Millwoodsizeof(int)
在 C 中也是实现定义的。然而,我们可以从 Haskell 调用带有 int
参数的函数,因为目标平台的 C ABI 是由平台供应商指定的。问题在于,一些供应商选择忽略 C99 扩展。一个合理的解决方案是在这些情况下将 _Bool
类似于 unsigned char
处理。 - Mikhail Glushenkov_Bool
类型的确切大小(而bool
映射到_Bool
)。你唯一知道的是它足够大以容纳值0
和1
。因此,它的二进制表示是与编译器相关的,这就是为什么我猜想它不在FFI支持库中的原因。#include <stdio.h>
#include <stdbool.h>
int main() {
printf("%d", sizeof(bool));
return 0;
}
% gcc -std=c99 -o test test.c
% ./test
1
在GCC中,bool
似乎被映射为char
。你看到的结果取决于编译器。
因此,如果你想要完全可移植性,最好为你的C函数编写一个包装器(wrapper),它将采用普通的int
并使用类型转换传递给函数。
CInt
和CLong
也不存在,因为它们也没有精确的大小要求。我们知道关于 int
的只是它至少必须支持从 -32767 到 32767 的值。 - Luc DantonCInt
和CLong
的基础类型被所有编译器支持,没有例外。但是对于bool
来说就不是这样了,因为它是C99扩展,一些最常用的编译器根本不支持C99。显然,良好的FFI实现不应该依赖于存在支持所有最新标准的理想编译器。 - Vladimir Matveev_Bool
可能会改变大小并不是问题,我们只需要让 CBool
(或其他)做同样的事情即可。 - Ben Millwood将参数设为bool
和将返回类型设为bool
之间存在差异。
int
是大多数基本C类型的安全替代品。但是对于bool类型,CChar很可能会做得更好。您可能希望阅读有关可变参数特性,...)
的文章,这是由printf
使用的。#include <stdbool.h>
type CBool = #{type bool}
cFalse, cTrue :: CBool
cFalse = 0
cTrue = 1
你还可以使用Foreign.Marshall.Utils中的toBool
和fromBool
函数在CBool
和Bool
之间进行转换。
关键在于#{type bool}
,它告诉hsc2hs
选择一个与C类型bool
大小相同的Haskell数值类型。在我的机器上,这个类型是Word8
。
自版本4.10.0.0
起,base
库包含了Foreign.C.Types.CBool
,对应于ghc-8.2
。
https://hackage.haskell.org/package/base-4.10.1.0/docs/Foreign-C-Types.html#t:CBool