簡體   English   中英

C ++ / VS2010中sprintf的異常行為

[英]Bizarre behavior from sprintf in C++/VS2010

我有一個非常簡單的類,它以固定的精度表示小數點后的數字,當我要格式化它時,我會執行以下操作:

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

令人驚訝的(至少對我來說),這是行不通的。 即使d.DENOMINATOR沒有將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都很長,所以%d不夠用。非常感謝Serge在下面的評論指出了問題,馬克隨后不久也提交了答案。)

幾乎可以肯定,您的術語組件是64位類型的(在64位系統上可能long ),該類型將被傳遞到非類型安全的sprintf 因此,當您創建一個中間int時,其大小是正確的,並且可以正常工作。

g ++會通過-Wall警告此問題以及許多其他有用的事情。 當然首選的解決方案是使用C ++ iostream進行格式化,因為它們完全是類型安全的。

另一種解決方案是將表達式的結果轉換為您告訴sprintf期望的類型,以便將適當數量的字節從內存中拉出。

最后,當幾乎每個編譯器都支持snprintf時,不要使用sprintf ,它可以防止各種愚蠢的錯誤。 您的代碼現在很好,但是當有人稍后對其進行修改並且在緩沖區末尾運行時,您可能需要花費數天來跟蹤損壞情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM