将 unsigned long 转换为字符串的缓冲区大小
Buffer size for converting unsigned long to string
参考问题和答案
here: 我可以使用这种方法,以便解决方案与平台无关吗?
char *buff = (char*) malloc(sizeof(unsigned long)*8);
sprintf(buff, "%lu", unsigned_long_variable);
我在这里获取缓冲区长度的值,因为它类似于无符号长变量。这种做法正确吗?
The C standard doesn't put an upper limit to the number of bits per char.
如果有人构建了一个 C 编译器,例如每个字符使用 2000 位,则输出可能会溢出缓冲区。
您应该使用 limits.h 中的 CHAR_BIT
而不是 8
。
此外,请注意,每 3 位需要(略少于)1 个字符,并且字符串终止符需要 1 个字节。
所以,像这样:
#include <limit.h>
char *buff = malloc(1 + (sizeof(unsigned long) * CHAR_BIT + 2) / 3);
sprintf(buff, "%lu", unsigned_long_variable);
不,这不是计算缓冲区大小的正确方法。
例如对于 4 字节无符号长整型,您的值最大为 2^32-1
这意味着 10 位十进制数字。所以你的缓冲区需要 11 个字符。
您正在分配 4 * 8 = 32。
正确的公式是
ceil(log10(2^(sizeof(unsigned long) * CHAR_BIT) - 1)) + 1
(log10
这里表示十进制对数)
一个好的(安全)估计是:
(sizeof(unsigned long) * CHAR_BIT + 2) / 3 + 1
因为 log10(2) 小于 0.33。
甚至尝试 计算缓冲区大小。
从 snprintf
开始,它会安全地告诉您需要多少个字符。然后你知道要分配多少字节来安全打印。
由于这是您不想一次又一次重复的几行代码,因此请编写一个函数 malloc_printf
来完全满足您的需求:在该函数中,调用 snprintf
使用 NULL 目标,然后 malloc
缓冲区,sprintf
进入 malloc
缓冲区,然后 return 它。为了使其更快并经常避免两次 snprintf
和 sprintf
调用,首先写入 256 个字符的缓冲区,这通常就足够了。
所以你的最终代码是
char* buff = malloc_printf ("%lu", unsigned_long_variable);
还可以使用 %s%s
格式进行快速、安全和简单的字符串连接。
您想知道需要多少个字符才能表示最大的可能 unsigned long
。正确吗?
为此,您正在尝试计算最大可能 unsigned long
:
sizeof(unsigned long)*8
这在几个方面是错误的。其一,sizeof
returns char
的倍数,不必是 8 位。您应该乘以 CHAR_BIT
(来自 <limits.h>
)。但即使那样也没有必要,因为同样的 header 已经提供了最大可能的值 -- UCHAR_MAX
.
那你就犯了一个错误:你的计算给出了 整数 表示 unsigned long
位 的大小.您想要的是字符串表示的字符的大小。这可以通过 log10()
函数(来自 <math.h>
)来实现:
log10( UCHAR_MAX )
这将为您提供一个 double
值,表示 UCHAR_MAX
中的(十进制)位数。这将是一个分数,您需要将其四舍五入 (1)(ceil()
为您完成)。
因此:
#include <math.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
char * buff = malloc( ceil( log10( UCHAR_MAX ) ) + 1 );
//...
}
总而言之,这很狡猾(我在写这篇文章时犯了 两个 错误,真丢脸——如果你在使用它时犯了错误,真丢脸) .它需要使用数学库来完成 snprintf( NULL, ... )
可以更轻松地为您做的事情,如您链接到的问答所示。
(1): log10( 9999 )
为 四 位数字给出 3.9999565...
。
简答:
#define INTEGER_STRING_SIZE(t) (sizeof (t) * CHAR_BIT / 3 + 3)
unsigned long x;
char buf[INTEGER_STRING_SIZE(x)];
int len = snprintf(buf, sizeof buf, "%lu", x);
if (len < 0 || len >= sizeof buf) Handle_UnexpectedOutput();
OP 对 sizeof(unsigned long)*8
的使用很弱。在 CHAR_BIT
(每个 char
的位数)很大(必须至少为 8)的系统上,sizeof(unsigned long)
可能是 1。1*8
char
对于 4294967295
(ULONG_MAX
的最小值)来说肯定太小了。
关注:sprintf()/snprintf()
鉴于 locale 问题,理论上,代码可能会打印额外的字符,如 4,294,967,295
,从而超出预期的缓冲区。除非出现非常严格的内存限制,否则建议使用 2 倍预期大小的缓冲区。
char buf[ULONG_STRING_SIZE * 2]; // 2x
int len = snprintf(buf, sizeof buf, "%lu", x);
打印一些无符号整数的预期最大字符串宽度为ceil(log10(unsigned_MAX)) + 1
。在unsigned long
的情况下,ULONG_MAX
的值肯定不会超过pow(2,sizeof (unsigned long) * CHAR_BIT) - 1
所以代码可以使用:
#define LOG10_2 0.30102999566398119521373889472449
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * LOG10_2 + 2)
// For greater portability, should use integer math.
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT / 3 + 2)
// or more precisely
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * 28/93 + 2)
如果指定了 有符号` 整数,则使用 +3
的简短回答。
参考问题和答案 here: 我可以使用这种方法,以便解决方案与平台无关吗?
char *buff = (char*) malloc(sizeof(unsigned long)*8);
sprintf(buff, "%lu", unsigned_long_variable);
我在这里获取缓冲区长度的值,因为它类似于无符号长变量。这种做法正确吗?
The C standard doesn't put an upper limit to the number of bits per char.
如果有人构建了一个 C 编译器,例如每个字符使用 2000 位,则输出可能会溢出缓冲区。
您应该使用 limits.h 中的 CHAR_BIT
而不是 8
。
此外,请注意,每 3 位需要(略少于)1 个字符,并且字符串终止符需要 1 个字节。
所以,像这样:
#include <limit.h>
char *buff = malloc(1 + (sizeof(unsigned long) * CHAR_BIT + 2) / 3);
sprintf(buff, "%lu", unsigned_long_variable);
不,这不是计算缓冲区大小的正确方法。
例如对于 4 字节无符号长整型,您的值最大为 2^32-1 这意味着 10 位十进制数字。所以你的缓冲区需要 11 个字符。
您正在分配 4 * 8 = 32。
正确的公式是
ceil(log10(2^(sizeof(unsigned long) * CHAR_BIT) - 1)) + 1
(log10
这里表示十进制对数)
一个好的(安全)估计是:
(sizeof(unsigned long) * CHAR_BIT + 2) / 3 + 1
因为 log10(2) 小于 0.33。
甚至尝试 计算缓冲区大小。
从 snprintf
开始,它会安全地告诉您需要多少个字符。然后你知道要分配多少字节来安全打印。
由于这是您不想一次又一次重复的几行代码,因此请编写一个函数 malloc_printf
来完全满足您的需求:在该函数中,调用 snprintf
使用 NULL 目标,然后 malloc
缓冲区,sprintf
进入 malloc
缓冲区,然后 return 它。为了使其更快并经常避免两次 snprintf
和 sprintf
调用,首先写入 256 个字符的缓冲区,这通常就足够了。
所以你的最终代码是
char* buff = malloc_printf ("%lu", unsigned_long_variable);
还可以使用 %s%s
格式进行快速、安全和简单的字符串连接。
您想知道需要多少个字符才能表示最大的可能 unsigned long
。正确吗?
为此,您正在尝试计算最大可能 unsigned long
:
sizeof(unsigned long)*8
这在几个方面是错误的。其一,sizeof
returns char
的倍数,不必是 8 位。您应该乘以 CHAR_BIT
(来自 <limits.h>
)。但即使那样也没有必要,因为同样的 header 已经提供了最大可能的值 -- UCHAR_MAX
.
那你就犯了一个错误:你的计算给出了 整数 表示 unsigned long
位 的大小.您想要的是字符串表示的字符的大小。这可以通过 log10()
函数(来自 <math.h>
)来实现:
log10( UCHAR_MAX )
这将为您提供一个 double
值,表示 UCHAR_MAX
中的(十进制)位数。这将是一个分数,您需要将其四舍五入 (1)(ceil()
为您完成)。
因此:
#include <math.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
char * buff = malloc( ceil( log10( UCHAR_MAX ) ) + 1 );
//...
}
总而言之,这很狡猾(我在写这篇文章时犯了 两个 错误,真丢脸——如果你在使用它时犯了错误,真丢脸) .它需要使用数学库来完成 snprintf( NULL, ... )
可以更轻松地为您做的事情,如您链接到的问答所示。
(1): log10( 9999 )
为 四 位数字给出 3.9999565...
。
简答:
#define INTEGER_STRING_SIZE(t) (sizeof (t) * CHAR_BIT / 3 + 3)
unsigned long x;
char buf[INTEGER_STRING_SIZE(x)];
int len = snprintf(buf, sizeof buf, "%lu", x);
if (len < 0 || len >= sizeof buf) Handle_UnexpectedOutput();
OP 对 sizeof(unsigned long)*8
的使用很弱。在 CHAR_BIT
(每个 char
的位数)很大(必须至少为 8)的系统上,sizeof(unsigned long)
可能是 1。1*8
char
对于 4294967295
(ULONG_MAX
的最小值)来说肯定太小了。
关注:sprintf()/snprintf()
鉴于 locale 问题,理论上,代码可能会打印额外的字符,如 4,294,967,295
,从而超出预期的缓冲区。除非出现非常严格的内存限制,否则建议使用 2 倍预期大小的缓冲区。
char buf[ULONG_STRING_SIZE * 2]; // 2x
int len = snprintf(buf, sizeof buf, "%lu", x);
打印一些无符号整数的预期最大字符串宽度为ceil(log10(unsigned_MAX)) + 1
。在unsigned long
的情况下,ULONG_MAX
的值肯定不会超过pow(2,sizeof (unsigned long) * CHAR_BIT) - 1
所以代码可以使用:
#define LOG10_2 0.30102999566398119521373889472449
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * LOG10_2 + 2)
// For greater portability, should use integer math.
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT / 3 + 2)
// or more precisely
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * 28/93 + 2)
如果指定了 有符号` 整数,则使用 +3
的简短回答。