[英]C : Printing big numbers
請考慮以下事項:
#include <stdio.h>
main() {
unsigned long long verybig = 285212672;
printf("Without variable : %llu\n", 285212672);
printf("With variable : %llu", verybig);
}
這是上述程序的輸出:
Without variable : 18035667472744448
With variable : 285212672
從上面可以看到,當printf
作為常量傳遞時,它會輸出一些巨大的錯誤數字,但是當該值首次存儲在變量中時, printf
輸出正確的數字。
這背后的原因是什么?
試試285212672ULL
; 如果你在沒有后綴的情況下編寫它,你會發現編譯器將它視為常規整數。 它在變量中工作的原因是因為整數在賦值中被強制轉換為unsigned long long
,因此傳遞給printf()
的值是正確的類型。
在你問之前,不,編譯器可能不夠智能,無法從printf()
格式字符串中的"%llu
”中找出它。 這是一個不同的抽象層次。 編譯器負責語言語法, printf()
語義不是語法的一部分,它是一個運行時庫函數(除了它包含在標准中之外,與你自己的函數沒有什么不同)。
對於32位int和64位unsigned long long系統,請考慮以下代碼:
#include <stdio.h>
int main (void) {
printf ("%llu\n",1,2);
printf ("%llu\n",1ULL,2);
return 0;
}
哪個輸出:
8589934593
1
在第一種情況下,兩個32位整數1和2被壓入堆棧, printf()
將其解釋為單個64位ULL值,2 x 2 32 + 1. 2
參數無意中包含在ULL值。
在第二個中,您實際上是推送64位1值和多余的32位整數2
,這將被忽略。
請注意,格式字符串與實際參數之間的“不合時宜”是一個壞主意。 就像是:
printf ("%llu %s %d\n", 0, "hello", 0);
可能會崩潰,因為%llu
將消耗32位"hello"
指針, %s
將嘗試取消引用最后的0
參數。 下面的“圖片”說明了這一點(我們假設單元格是32位,“hello”字符串存儲在0xbf000000。
What you pass Stack frames What printf() uses
+------------+
0 | 0 | \
+------------+ > 64-bit value for %llu.
"hello" | 0xbf000000 | /
+------------+
0 | 0 | value for %s (likely core dump here).
+------------+
| ? | value for %d (could be anything).
+------------+
值得指出的是,有些編譯器會針對這種情況提供有用的警告 - 例如,這就是GCC對您的代碼所說的內容:
x.c: In function ‘main’:
x.c:6: warning: format ‘%llu’ expects type ‘long long unsigned int’, but argument 2 has type ‘int’
285212672
是一個int
值。 printf
期望一個unsigned long long
,你傳遞一個int
。 因此,它會從堆棧中獲取更多的字節,而不是傳遞實際值並打印垃圾。 當你將它放在一個unsigned long long
變量中,然后將它傳遞給函數之前,它將在賦值行中被提升為unsigned long long
,並將該值傳遞給printf
,它正常工作。
數據類型只是一種解釋內存位置內容的方法。
在第一種情況下,常量值作為int存儲在只讀存儲器位置中,printf嘗試將該地址解釋為8字節位置,因為它被指示存儲的值在其打印垃圾值的過程中很長。
在第二種情況下,printf嘗試將長long值解釋為8個字節,並打印出預期的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.