缓冲区大小转换无符号长串

问题描述:

在提到的问题,答案 here:我可以用这个方法,使该解决方案将是平台无关的。缓冲区大小转换无符号长串

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

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

+1

请查看[为什么不投射](http://stackoverflow.com/q/605845/2173917)'malloc()'和'C'中的系列的返回值。 –

+0

@SouravGhosh:谢谢你的提示,但这与我的怀疑有关吗?!我试图了解上述方法是否独立于平台。 我想了解上述方法是否正确。如果不正确,纯粹为了理解和学习! –

+3

@SouravGhosh,你的习惯是在你身边张贴这个不相关的,值得商榷的建议吗? – gnasher729

您想知道需要多少个字符来表示最大可能的unsigned long。正确?

为此,您要计算最大可能unsigned long

sizeof(unsigned long)*8 

也就是说在几个方面有缺陷。首先,sizeof返回char的倍数,这不必是8位。您应该乘以CHAR_BIT(来自<limits.h>)。但即使这样也不是必须的,因为这个标头已经提供了最大的可能值 - UCHAR_MAX

然后你犯了一个错误:你的计算给出了位的unsigned long整数表示的大小。你想要字符串的大小字符的表示。这可以通过(从<math.h>)的log10()功能来实现:

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); 
    //... 
} 

总而言之,这是很狡猾的(我做了2个错误而写了这一点,可耻的是我 - 如果你使用这个时候犯错,可耻的是你) 。并且它需要将数学库用于snprintf(NULL, ...)可以更轻松地为您做的事情,正如您链接到的Q &所示。


(1):log10(9999)给出3.9999565...为位数字号码。

+1

但是与解释相反,你的代码并没有**凑成整数。或者,你忘记了尾部0.此外,C的“log”是自然对数。我们需要'log10'。 –

+1

通用建议:当源代码中出现的数字不是“1”或“0”时,这就是代码异味,又名[未命名数字常量](https://en.wikipedia.org/wiki/Magic_number_%28programming %29个#Unnamed_numerical_constants)。这表明你做错了什么。 – DevSolar

+0

@undur_gongor:Hurrr ...“post before post”的另一课。我打算'+ 1'完成整合,并立即忘记了空字节终止符。 :-D – DevSolar

The C standard doesn't put an upper limit to the number of bits per char

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

相反的8你应该使用CHAR_BIT从limits.h中。

另外请注意,你需要(性能稍微低于)每3位1个char和你需要一个字符串结束1个字节。

所以,这样的事情:

#include <limit.h> 

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

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

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 

因为日志10(2)小于0.33。

+1

使用'CHAR_BIT'去除有关字符大小的假设 –

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

开始snprintf,这将安全地告诉你需要多少个字符。然后你就知道要分配多少个字节才能安全打印。

因为这是几行代码,你不想一遍又一遍重复,写你想要做的是什么功能malloc_printf:这样的函数,调用snprintf用NULL目的地,然后malloc缓冲区,sprintf放入malloc缓冲区,然后返回。为了使速度更快并且经常避免两个调用,首先写入256个字符的缓冲区,这通常就足够了。

所以你的最终代码会

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

也并使用格式%s%s,例如快速,安全和简便的字符串连接。

+0

感谢您的建议。事实上,我也在我的代码中使用了它。但其他答案清除了我的怀疑。谢谢btw。 –

简短的回答:

#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*8char肯定是用于4294967295(对于ULONG_MAX最小值)太小。

有关:sprintf()/snprintf()鉴于区域问题,从理论上讲,代码可以打印样4,294,967,295额外字符等超过预期的缓冲区。除非出现非常严格的内存限制,否则推荐一个2x预期大小的缓冲区

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万一签署指定`整数。