[英]Unexpected types from UINT32_C, UINTN_C
7.20.4.1最小寬度整數常量的宏
...宏UINTN_C(value)
應擴展為對應於uint_leastN_t
類型的整數常量表達式。 例如,如果uint_least64_t
是unsigned long long int
類型的名稱,則UINT64_C(0x123
)可能會擴展為整數常量0x123ULL
。 C11dr§7.20.4.11
UINTN_C()
和朋友的類型不符合預期。 請參閱代碼輸出中的“預期”注釋。
A)我的編譯器實現是錯誤的,常量類型應該是uint_leastN_t
嗎?
要么
B)來自UINTN_C(value)
的常量類型是否應該是uint_leastN_t
, int
, unsigned
和類型編碼值所需的最小值?
要么
C)別的什么?
我原以為常量的類型對應於uint_leastN_t
,但在2個條件下似乎不是這樣:
** 1如果宏對應的類型低於int/unsigned
,則常量為int/unsigned
** 2如果該值超出uint_leastN_t
的范圍,則類型變為更寬的類型常量。
§6.4.4.1“整數常量的類型是相應列表中可以表示其值的第一個...(后面是長列表)。
#include <limits.h>
#include <stdio.h>
#define type_of(X) _Generic((X), \
unsigned long long: "unsigned long long", \
unsigned long: "unsigned long", \
unsigned: "unsigned", \
int: "int", \
unsigned short: "unsigned short", \
default: "?" \
)
int main() {
uint_least16_t u16 = 0;
uint_least32_t u32 = 0;
uint_least64_t u64 = 0;
printf("%zu %s\n", sizeof(u16), type_of(u16));
printf("%zu %s\n", sizeof(u32), type_of(u32));
printf("%zu %s\n", sizeof(u64), type_of(u64));
puts("");
printf("%zu %s\n", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
printf("%zu %s\n", sizeof UINT16_C(0), type_of(UINT16_C(0)));
printf("%zu %s\n", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
printf("%zu %s\n", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
printf("%zu %s\n", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
printf("%zu %s\n", sizeof UINT32_C(0x123456789), type_of(UINT32_C(0x123456789)));
return 0;
//round_frac_test(-2.05446162500000000e+06, 205);
round_frac_test(fp_rand(), 6);
round_frac_tests(10000);
puts("Done");
return 0;
}
產量
2 unsigned short
4 unsigned
8 unsigned long long
2 unsigned short
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **2
4 unsigned
8 unsigned long long // Expected 4 unsigned, see **2
我正在使用(GNU C11(GCC)版本5.4.0)
在組建這篇文章時,我傾向於B,但我正在尋找你理性的確認 - 另一種方式。 如果B是這樣,令人失望的部分是UINTN_C()
可能導致簽名類型。
我想這就是“最小寬度”部分的含義。
這一點在父節小節7.20.4中有所涉及。
在您引用的部分中:
宏
UINTN_C(value)
將擴展為對應於類型uint_leastN_t
的整數常量表達式。
它說“ 對應於 ”,而不是擴展實際上是那種類型。 “ 對應於 ”的含義在7.20.4p3中解釋:
其中一個宏的每次調用都應擴展為適合在
#if
預處理指令中使用的整數常量表達式。 表達式的類型應與根據整數提升轉換的相應類型的表達式具有相同的類型。 表達式的值應該是參數的值。
由於#if
在用於#if
指令,因此它們不能使用強制轉換(預處理器不了解強制轉換或類型名稱)。
在實踐中,這樣的常量表達式幾乎總是被隱式轉換為適當的類型,因此其實際類型與您可能期望的不同的事實通常不是問題。
至於uint_leastN_t
范圍之外的值,在7.20.4p2中也包含在父子小節中:
這些宏的任何實例中的參數都應是未填充的整數常量(如6.4.4.1中所定義),其值不超過相應類型的限制。
這是約束之外的“必須”,因此違反它會導致未定義的行為。 不要那樣做。
(在閱讀C標准時,通常最好檢查一下家長小節的措辭,這些措辭可能會澄清或覆蓋您正在閱讀的內容。我自己也被這個問題所困擾。)
在具有16位short
整數和32位整數的主機上, unsigned short
整數被提升為int
。 所以這些宏定義為:
#define INT16_C(x) (x)
#define UINT16_C(x) (x)
沒有'U'后綴為unsigned short
如果int可以表示原始類型的所有值(由寬度限制,對於位字段),則該值將轉換為int;
這些宏只擴展為相應的常量(或使用更常用語言的整數文字),並且不創建任何對象,並且必須在#if中使用。 所以不允許演員陣容。 宏也不執行任何范圍檢查。
int16_t x0 = 123;
uint16_t x1 = 123; // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U; //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL;
uint64_t x5 = 9237372036854775807ULL; //same as above
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.