问题描述
我想为 sprintf
创建一个整数缓冲区(在本例中为 unsigned int
)。一种简单而错误的方法是:
I want to create a buffer for sprintf
ing a integer (in this case an unsigned int
). A simple and misguided approach would be:
char buf[11];
sprintf(buf, "%u", x);
如果我们知道 unsigned int
最多只有 33
位宽,但是如果我们要适应所有奇怪的体系结构怎么办?我能想到的最好的方法是:
This works great if we know that unsigned int
is at most 33
bits wide, but what if we want to accomodate all wierd architectures? The best I can come up with is:
char buf[(CHAR_BIT*sizeof(unsigned)+5)/3];
sprintf(buf, "%u", x);
我非常有信心这对任何实施都有效。 CHAR_BIT * sizeof(unsigned)
是(上限) unsigned
中的位数。然后,我加2并除以3以找到八进制表示形式的位数,最后为NUL终止加一个。这意味着缓冲区足以打印以八进制表示的数字,并且由于十进制表示使用的数字不多于八进制,因此十进制表示也足够。
I'm quite confident this will work on any implementation. CHAR_BIT*sizeof(unsigned)
is (an upper bound for) the number of bits in an unsigned
. Then I add two and divide 3 to find the number of digits in octal representation and finally add one for the NUL-termination. This means the buffer is enough for printing the number in octal and since decimal representation uses no more digits than octal it will be enough for decimal representation too.
有没有更好的选择?做到这一点的方法?更好的是,我的意思是一种生成较小的缓冲区而又不会冒缓冲区溢出的风险的方法,无论 x
的值是多少(即使面对恶意构造但符合标准的实现)。我的方法将为32位 unsigned
生成12- char
缓冲区,尽管 11
就足够了。
Is there a better way to do this? By better I mean a way producing smaller buffer without risking a buffer overrun no matter what value x
has (even in face of malicious constructed yet standard conforming implementation). My approach would produce a 12-char
buffer for 32-bit unsigned
despite the fact that 11
would be enough.
推荐答案
编译不同的相关注释,最值得注意的是:
Compiling different relevant comments, most notably:
- 。
- 的评论对其进行了很好的总结: n个二进制数字需要ceil(n * ln(2)/ ln(10))≈ceil(n * 0.301)
- the math question.
- Martin R's comment that summarizes it well: "n binary digits require ceil(n*ln(2)/ln(10)) ≈ ceil(n * 0.301)"
您有答案:
#define MAX_DECIMAL_SIZE(x) ((size_t)(CHAR_BIT * sizeof(x) * 302 / 1000) + 1)
char buffer[MAX_DECIMAL_SIZE(unsigned int) + 1];
sprintf(buffer, "%u", x);
/* MAX_DECIMAL_SIZE(uint8_t) => 3
* MAX_DECIMAL_SIZE(uint16_t) => 5
* MAX_DECIMAL_SIZE(uint32_t) => 10
* MAX_DECIMAL_SIZE(uint64_t) => 20
* MAX_DECIMAL_SIZE(__uint128_t) => 39 */
302/1000
来了从 ln(2)/ ln(10)
中取整。您可以从 0.3010299956639812…
中获取更多数字,以提高精度,但是在使用32768位系统左右之前,这是过分的。续分数也可以工作(请参阅下面的Martin R评论)。无论哪种方式,请注意 CHAR_BIT * sizeof(x)*<您选择的分子>
不要太大,并记住结果必须大于实际值。
The 302/1000
comes from ln(2)/ln(10)
, rounded up. You can take more digits, from 0.3010299956639812…
for more precision, but that's overkill until you work with 32768-bits systems or so. Continued fractions work too (see Martin R's comment below). Either way, be careful that CHAR_BIT * sizeof(x) * <your chosen numerator>
is not too large and remember the result must be greater than the actual value.
如果您确实坚持使用八进制表示,只需将乘数更改为 ln(2)/ ln(8)
(就是and),您将获得所需的八进制数字。
And if you really insist on octal representation, just change the multiplier to ln(2)/ln(8)
(that's ⅓) and you'll have the number of octal digits required.
这篇关于有没有更好的方法来设置用于打印整数的缓冲区的大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!