用于将unsigned long转换为string的缓冲区大小

时间:2015-07-21 10:12:07

标签: c string pointers malloc

参考问题和答案 here:我可以使用此方法,以便解决方案与平台无关。

char *buff = (char*) malloc(sizeof(unsigned long)*8);
sprintf(buff, "%lu", unsigned_long_variable);

这里我得到缓冲区长度的值,因为它类似于unsigned long变量。这种方法是否正确?

5 个答案:

答案 0 :(得分:3)

不要尝试来计算缓冲区大小。

snprintf开始,它会安全地告诉您需要多少个字符。然后你知道要分配多少字节来安全打印。

由于这是您不想一次又一次重复的几行代码,请编写一个完全符合您要求的函数malloc_printf:在该函数中,调用snprintf使用NULL目标,然后将malloc缓冲区sprintf放入malloc缓冲区,并返回它。为了使其更快并且经常避免两个snprintfsprintf调用,首先写入256个字符的缓冲区,这通常就足够了。

所以你的最终代码是

char* buff = malloc_printf ("%lu", unsigned_long_variable);

例如,使用格式%s%s进行快速,安全且简单的字符串连接。

答案 1 :(得分:1)

column map

如果有人构造一个C编译器,每个字符使用例如2000位,则输出可以溢出缓冲区。

您应该使用来自limits.h的8而不是CHAR_BIT

另外,请注意,每3位需要(略小于)1个字符,字符串终止符需要1个字节。

所以,像这样:

#include <limit.h>

char *buff = malloc(1 + (sizeof(unsigned long) * CHAR_BIT + 2) / 3);
sprintf(buff, "%lu", unsigned_long_variable);

答案 2 :(得分:1)

不,这不是计算缓冲区大小的正确方法。

E.g。对于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。

答案 3 :(得分:1)

您想知道需要多少个字符才能代表最大的unsigned long。正确的吗?

为此,您正在尝试计算可能的最大unsigned long

sizeof(unsigned long)*8

这在几个方面都有问题。例如,sizeof返回char的倍数,不需要是8位。您应该与CHAR_BIT(来自<limits.h>)相乘。但即使这样也没有必要,因为相同的标题已经提供了最大可能的值 - 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, ... )可以更轻松地为您做的事情,如您链接到的Q&amp; A所示。

(1):log10( 9999 )为{em>四 - 数字提供3.9999565...

答案 4 :(得分:1)

简短回答:

#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 char4294967295来说肯定太小了(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的简短答案。