使用 sprintf 打印 size_t 需要多少个字符?

How many chars do I need to print a size_t with sprintf?

我想做这样的事情:

char sLength[SIZE_T_LEN];

sprintf(sLength, "%zu", strlen(sSomeString));

也就是说,我想在缓冲区中打印一个 size_t 类型的值。问题是:SIZE_T_LEN 的值应该是多少?关键是要知道所需的最小大小,以确保永远不会发生溢出。

sizeof(size_t) * CHAR_BIT(来自limits.h)给出位数。对于十进制输出,为了安全起见,请使用(粗略的)较低估计值,即每个数字 3(十六进制为 4)位。不要忘记为字符串的 nul 终止符添加 1

所以:

#include <limits.h>

#define SIZE_T_LEN ( (sizeof(size_t) * CHAR_BIT + 2) / 3 + 1 )

这会产生一个 size_t 类型的值本身。在典型的 8/16/32/64 位平台上,不需要 + 2size_t 的最小可能大小是 16 位)。这里的错误已经大到足以产生正确截断的结果。

请注意,这给出了上限并且由于使用 CHAR_BIT 是完全可移植的。要获得精确值,您必须使用 log10(SIZE_MAX)(请参阅 JohnBollinger 的回答)。但这会产生一个浮点数,可能会在 run-time 处计算,而上面的版本是 compile-time 评估的(并且可能已经比粗略估计花费更多的堆栈)。除非你有一个非常受 RAM 限制的系统,否则没关系。在这样的系统上,您无论如何都应该避免使用 stdio

为了绝对安全起见,您可能需要使用 snprintf(但这不是必需的)。

如果可以使用snprintf,请使用:

int len = snprintf (NULL, 0, "%zu", strlen (sSomeString));

字符串终止符 space 的确切答案是

 log10(SIZE_MAX) + 2

其中 SIZE_MAX 宏在 stdint.h 中声明。不幸的是,这不是 compile-time 常量(由于使用了 log10())。如果你需要一个 compile-time 常量,它是在 编译时计算的,那么你可以使用这个:

sizeof(size_t) * CHAR_BIT * 3 / 10 + 2

这给出了 size_t 至少 256 位的正确答案。它基于 210 非常接近 1000 的事实。在一些大量的位上它会太小一个,而对于更多的位数它会进一步落后.如果您担心这么大 size_t 那么您可以在结果中添加一个甚至两个。

在使用 8 位表示字符的系统上,

sizeof(size_t)为2,则最大值为:65535
如果sizeof(size_t)为4,则最大值为:4294967295
如果sizeof(size_t)为8,则最大值为:18446744073709551615
如果sizeof(size_t)为16,则最大值为:3.4028237e+38

您可以使用该信息使用 pre-processor 来提取字符串的最大大小。

示例程序:

#include <stdio.h>

#ifdef MAX_STRING_SIZE
#undef MAX_STRING_SIZE
#endif

// MAX_STRING_SIZE is 6 when sizeof(size_t) is 2
// MAX_STRING_SIZE is 11 when sizeof(size_t) is 4
// MAX_STRING_SIZE is 21 when sizeof(size_t) is 8
// MAX_STRING_SIZE is 40 when sizeof(size_t) is 16
// MAX_STRING_SIZE is -1 for all else. It will be an error to use it 
// as the size of an array.

#define MAX_STRING_SIZE (sizeof(size_t) == 2 ? 6 : sizeof(size_t) == 4 ? 11 : sizeof(size_t) == 8 ? 21 : sizeof(size_t) == 16 ? 40 : -1)

int main()
{
   char str[MAX_STRING_SIZE];
   size_t a = 0xFFFFFFFF;

   sprintf(str, "%zu", a);
   printf("%s\n", str);

   a = 0xFFFFFFFFFFFFFFFF;
   sprintf(str, "%zu", a);
   printf("%s\n", str);
}

输出:

4294967295
18446744073709551615

它很容易适应使用 16 位表示字符的系统。