[英]printf with a size_t using the FFI
要使用printf
在C中打印size_t
整數,轉換格式化程序為%zu
。
但是當我使用帶有%zu
printf
時,通過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(2 32 )的值,因為這是unsigned long
的保證最小范圍。 請注意,演員陣容在這里非常重要。 因為printf()
是一個可變函數,所以原型看起來像printf(const char *fmt, ...)
,所以沒有可用的編譯器的類型信息 - 因此無法進行自動轉換。
如果問題是MSVCRT.DLL,並且你想要堅持使用C99或更高版本, 我建議在早期的答案中使用inttypes.h
的方法 。 這永遠不會在Windows上打印錯誤的值(並且仍然需要在其他平台上使用符合C99的標准庫)。
當沒有實現"%zu"
,替代方案是轉換為某種寬類型並打印,具有適度的截斷風險。
size_t sz = foo();
printf("%lu\n", (unsigned long) sz); // risk of truncation.
代碼可以嘗試其他整數寬類型,如uintmax_t
和unsigned long long
,但如果沒有實現"%zu"
,則可能還沒有實現"%ju"
和"%llu"
。
通過部分打印可以避免截斷。
printf("%lX%08lX\n",
(unsigned long) (sz/0x10000u/0x10000u), (unsigned long) (sz & 0xFFFFFFFFu));
// remote truncation risk remains.
printf("%lu%09lu\n",
(unsigned long) (sz/1000000000u), (unsigned long) (sz%1000000000u));
可以使用更復雜的代碼來避免前導數字。
我想提供另一種方法來處理不符合C99 / C11標准但仍提供64位或更寬類型的系統。
導入並包含一個stdint.h/inttypes.h
旨在將舊系統橋接到新的C99標准。
示例: C99 stdint.h標頭和MS Visual Studio
然后施放到他們可用的廣泛類型
#if SIZE_MAX > ULONG_MAX
// Include from the standard location or wherever the imported included files are saved.
#include <stdint.h>
#include <inttypes.h>
void printzu(){
size_t x = 666;
printf("x=%" PRIuMAX "\n", (uint_max_t) x);
}
#else
void printzu(){
size_t x = 666;
printf("x=%lu\n", (unsigned long) x);
}
#endif
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.