缓冲区大小转换无符号长串
在提到的问题,答案 here:我可以用这个方法,使该解决方案将是平台无关的。缓冲区大小转换无符号长串
char *buff = (char*) malloc(sizeof(unsigned long)*8);
sprintf(buff, "%lu", unsigned_long_variable);
这里我得到缓冲区长度的值,因为它将类似于无符号长变量。这种方法是否正确?
您想知道需要多少个字符来表示最大可能的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...
为位数字号码。
但是与解释相反,你的代码并没有**凑成整数。或者,你忘记了尾部0.此外,C的“log”是自然对数。我们需要'log10'。 –
通用建议:当源代码中出现的数字不是“1”或“0”时,这就是代码异味,又名[未命名数字常量](https://en.wikipedia.org/wiki/Magic_number_%28programming %29个#Unnamed_numerical_constants)。这表明你做错了什么。 – DevSolar
@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。
使用'CHAR_BIT'去除有关字符大小的假设 –
甚至不要尝试来计算缓冲区大小。
开始snprintf
,这将安全地告诉你需要多少个字符。然后你就知道要分配多少个字节才能安全打印。
因为这是几行代码,你不想一遍又一遍重复,写你想要做的是什么功能malloc_printf
:这样的函数,调用snprintf
用NULL目的地,然后malloc
缓冲区,sprintf
放入malloc
缓冲区,然后返回。为了使速度更快并且经常避免两个调用,首先写入256个字符的缓冲区,这通常就足够了。
所以你的最终代码会
char* buff = malloc_printf ("%lu", unsigned_long_variable);
也并使用格式%s%s
,例如快速,安全和简便的字符串连接。
感谢您的建议。事实上,我也在我的代码中使用了它。但其他答案清除了我的怀疑。谢谢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*8
char
肯定是用于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
万一签署指定`整数。
请查看[为什么不投射](http://stackoverflow.com/q/605845/2173917)'malloc()'和'C'中的系列的返回值。 –
@SouravGhosh:谢谢你的提示,但这与我的怀疑有关吗?!我试图了解上述方法是否独立于平台。 我想了解上述方法是否正确。如果不正确,纯粹为了理解和学习! –
@SouravGhosh,你的习惯是在你身边张贴这个不相关的,值得商榷的建议吗? – gnasher729