我想做这样的事情:
char sLength[SIZE_T_LEN];
sprintf(sLength, "%zu", strlen(sSomeString));
也就是说,我想在缓冲区中打印size_t
类型的值。问题是:SIZE_T_LEN
的价值应该是多少?关键是要知道所需的最小尺寸,以确保永远不会发生溢出。
答案 0 :(得分:8)
sizeof(size_t) * CHAR_BIT
(来自limits.h
)给出位数。对于十进制输出,使用每个数字的(粗略)低估计3(十六进制4)位在安全端。不要忘记为字符串的1
终止符添加nul
。
所以:
#include <limits.h>
#define SIZE_T_LEN ( (sizeof(size_t) * CHAR_BIT + 2) / 3 + 1 )
这会产生类型size_t
本身的值。在典型的8/16/32/64位平台上,+ 2
不是必需的(size_t
的最小可能大小为16位)。这里的错误已经足够大,可以产生正确的截断结果。
请注意,这会给出一个上限,并且由于使用CHAR_BIT
而完全可移植。要获得准确的值,您必须使用log10(SIZE_MAX)
(请参阅JohnBollinger的答案)。但是这产生了一个浮点数并且可能在运行时计算,而上面的版本是编译时评估的(并且可能比粗略估计的成本更多)。除非你有一个RAM限制系统,否则没问题。在这样的系统上,你应该避免使用stdio
。
为了绝对安全起见,您可能希望使用snprintf
(但这不是必需的)。
答案 1 :(得分:3)
确定字符串终结符空间的确切答案是
log10(SIZE_MAX) + 2
SIZE_MAX
中声明了stdint.h
宏。不幸的是,这不是编译时常量(由于log10()
的使用)。如果你需要一个在编译时计算的编译时常量,那么你可以使用它:
sizeof(size_t) * CHAR_BIT * 3 / 10 + 2
这为size_t
提供了至少256位的正确答案。它基于2 10 非常接近1000的事实。在一些大的位上,它将太小一个,而对于更大的位数,它将进一步下降背后。如果您担心这么大size_t
,那么您可以在结果中添加一个甚至两个。
答案 2 :(得分:2)
如果您可以使用snprintf,请使用:
int len = snprintf (NULL, 0, "%zu", strlen (sSomeString));
答案 3 :(得分:0)
在使用8位表示char的系统上
如果sizeof(size_t)
为2,则最大值为:65535
如果sizeof(size_t)
为4,则最大值为:4294967295
如果sizeof(size_t)
为8,则最大值为:18446744073709551615
如果sizeof(size_t)
为16,则最大值为:3.4028237e + 38
您可以使用该信息使用预处理器提取字符串的最大大小。
示例程序:
#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位表示char的系统。