2012-01-12 166 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,它可以防止各種愚蠢的錯誤。你的代碼現在沒有問題,但是當稍後有人修改它時,它會在緩衝區結束時運行,你可能會花費數天的時間來追蹤損壞情況。