为了在 C 语言中使用 printf
打印一个 size_t
整数,转换格式化程序是 %zu
。
然而,当我将 printf
与 %zu
一起使用时,通过 FFI 调用 Haskell 中的 C 函数会打印 zu
而不是整数。如何解决?
最小示例
文件 zu.c
#include <stdio.h>
void printzu(){
size_t x = 666;
printf("x=%zu", x);
}
模块 Lib.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Lib
where
import Foreign
foreign import ccall unsafe "printzu" printzu' :: IO ()
测试
Prelude> import Lib
Prelude Lib> printzu'
x=zu
最佳答案
由于 printf()
是 C 标准库的一部分,它通常在某些运行时库中实现。当它被动态链接时,如果根据哪个进程调用代码,链接了不同版本的库,则可以使用相同的代码产生这样的效果。如果 %zu
不工作,它是一个不支持 C99 的旧版本。
在 Windows 上,它很可能是系统的 MSVCRT.DLL,它不再供公众使用,但与旧的 MS Visual C 6 版本保持兼容。例如 MinGW 默认链接到那个库,所以你不需要发布你自己的 C 运行时。这当然有将库函数限制为 C89/C90 的缺点。
打印 size_t
的一个通常相当安全的做法是将其转换为 unsigned long
并打印:
size_t x = 666;
printf("x=%lu", (unsigned long)x);
这只会给出错误的结果,如果
- 该平台实际上有一个比
unsigned long
更大的size_t
(这是真的,例如对于具有 LLP64 数据模型的 64 位系统,不幸的是,win64)和 - 您在运行时确实有一个不适合
unsigned long
的大小。该值必须至少大于 4G (232),因为这是unsigned long
的保证最小范围。
请注意 Actor 阵容在这里非常重要。因为 printf()
是一个可变参数函数,原型(prototype)看起来就像 printf(const char *fmt, ...)
,所以编译器没有可用的类型信息 - - 因此无法进行自动转换。
如果问题具体出在 MSVCRT.DLL 上,而您一般想坚持使用 C99 或更高版本,I suggested a method using inttypes.h
in an earlier answer .这将永远不会在 Windows 上打印错误的值(并且在其他平台上仍然需要符合 C99 的标准库)。
关于c - 使用 FFI 的带有 size_t 的 printf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49942879/