你的第二個例子是不是有效的C99,看起來像C++。也許你想要的是演員,即(int32_t)(a/UINT64_C(1000000000))
?
有a/UINT64_C(1000000000)
和a/1000000000
之間的差異?不,他們會以相同的操作結束。但我不認爲這真的是你的問題。
我認爲你的問題歸結到會出現什麼整數文字的類型「10億」是什麼?它會是一個int32_t或int64_t? C99中的答案來自§6.4.4.1第5段:
整數常量的類型是其中可以表示其值的對應列表的第一個。
對於無後綴十進制常量,該列表是int
,long int
,long long int
。因此,第一個文字幾乎肯定會是一個int
(取決於一個int
的規模,這將可能是32位,併爲此大到足以容納一個十億)。帶有UINT64_C宏的第二個字面值可能是unsigned long
或unsigned long long
,具體取決於平臺。它將是與uint64_t
相對應的任何類型。
所以類型的常量是不一樣的。第一個將被簽名,而第二個未簽名。第二個很可能會有更多的「長」,這取決於編譯器的基本int類型的大小。
在您的例子,它使沒有區別的文字有不同的類型,因爲/
運營商將需要促進字面來的a
類型(因爲a
將等於或大於秩比字面在任何情況下) 。這就是爲什麼我不認爲這真的是你的問題。
有關爲何UINT64_C()
會的問題,考慮如果文字結果的變化都提升到一個更大的類型的表達式的例子。即,文字的本地類型會發生溢出。
int32_t a = 10;
uint64_t b = 1000000000 * a; // overflows 32-bits
uint64_t c = UINT64_C(1000000000) * a; // constant is 64-bit, no overflow
爲了計算c
,編譯器將需要促進a
到uint64_t
並執行64位乘法。但是要計算b
,編譯器將使用32位乘法,因爲這兩個值都是32位。
在最後一個例子,我們可以使用強制的,而不是宏觀:
uint64_t c = (uint_least64_t)(1000000000) * a;
這將迫使也是乘法至少爲64位。
爲什麼你會使用宏而不是鑄造文字?一種可能性是因爲小數文字被簽名。假設你想要一個不能表示爲一個有符號值的常量?例如:
uint64_t x = (uint64_t)9888777666555444333; // warning, literal is too large
uint64_t y = UINT64_C(9888777666555444333); // works
uint64_t z = (uint64_t)(9888777666555444333U); // also works
另一種可能性是預處理器表達式。一個強制轉換不是用於#if
指令表達式的合法語法。但是UINTxx_C()
宏是。
由於宏使用粘貼到文字上的後綴,並且沒有後綴,所以可能會發現UINT16_C(x)和UINT32_C(x)是相同的。這給出了結果(uint_least16_t)(65537) != UINT16_C(65537)
。不是人們所期望的。事實上,我很難看到它如何符合C99§7.18.4.1:
宏UINTN_C(值)應擴展爲與uint_leastN_t類型對應的整型常量表達式。
這是不好的編輯您的問題,以便它使現有答案中的問題無效。 –
另外,我很好奇爲什麼你問的是舊的C99標準,而不是「通用C」或C11標準。當然,''和''設施不是C90的一部分,但現在C99也很老舊。 –
@JonathanLeffler我修正了編輯問題。我問的是C99,因爲它是ANSI C之後最廣泛支持的標準,並且是我正在使用的標準。如果所有的編譯器都支持C11,那麼世界會更好,但事實並非如此...... – user3368561