2012-01-12 245 views
0

我有一个表示十进制#固定精度的超简单的类,而当我想格式化我做这样的事情:怪异行为

assert(d.DENOMINATOR == 1000000); 
char buf[100]; 
sprintf(buf, "%d.%06d", d._value/d.DENOMINATOR, d._value % d.DENOMINATOR); 

令人惊讶的是(对我来说至少)这不起作用。即使dDENOMINATOR不能均分d._value,%06d术语也会全部为0。如果我在格式字符串中添加了额外的%d,我会看到第三个地方显示正确的值 - 这就像是在我的两个人之间秘密地创建了一个额外的参数。

如果我计算sprintf调用之外的两个术语,那么所有的表现都是我所期望的。我想用一个更简单的测试用例来重现这一点:

char testa[200]; 
char testb[200]; 
int x = 12345, y = 1000; 
sprintf(testa, "%d.%03d", x/y, x%y); 
int term1 = x/y, term2 = x%y; 
sprintf(testb, "%d.%03d", term1, term2); 

...但这个工作正常。所以我完全不知道到底发生了什么,未来如何避免它,等等。谁能为我阐明这一点?

(编辑:问题最终是因为d._value和d.DENOMINATOR都是long long,所以%d不足以感谢Serge对此的评论,指出了问题,Mark此后不久提交了答案)

+5

什么是“d”类型的定义 – 2012-01-12 21:37:15

+2

请显示输出示例。此外,d; _value和d.DENOMINATOR的类型是什么? – 2012-01-12 21:37:25

+0

你最好向我们展示这个超级简单的实现。 – 2012-01-12 21:39:17

回答

3

几乎可以肯定,您的术语组件是64位类型(可能是在64位系统上的long),它正在传入非类型安全的sprintf。因此,当你创建一个中间int的大小是正确的,它工作正常。

g ++会警告这个和许多其他有用的东西-Wall。首选的解决方案当然是使用C++ iostream来进行格式化,因为它们完全是类型安全的。

替代解决方案是将表达式的结果转换为您告诉sprintf预期的类型,以便它将适当数量的字节拉出内存。

最后,几乎每个编译器都支持snprintf时,千万不要使用sprintf,它可以防止各种愚蠢的错误。你的代码现在没有问题,但是当稍后有人修改它时,它会在缓冲区结束时运行,你可能会花费数天的时间来追踪损坏情况。