[英]Why do implementations of “stdint.h” disagree on the definition of UINT8_C?
UINT8_C
宏在“stdint.h”中定義,具有以下規范 : 宏UINTN_C(value)
應擴展為對應於uint_leastN_t
類型的整數常量表達式。
然而,在野外,實現方式有所不同:
#define UINT8_C(value) ((uint8_t) __CONCAT(value, U)) // AVR-libc
#define UINT8_C(x_) (static_cast<std::uint8_t>(x_)) // QP/C++
#define UINT8_C(c) c // GNU C Library
前兩個實現似乎大致相同,但第三個實現的行為不同:例如,以下程序使用AVR-libc和QP / C ++打印1
,但使用glibc打印-1
(因為有符號值的右移傳播符號位)。
std::cout << (UINT8_C(-1) >> 7) << std::endl; // prints -1 in glibc
UINT16_C
的實現顯示相同的行為,但不顯示UINT32_C
,因為它的定義包括U
后綴:
#define UINT32_C(c) c ## U
有趣的是,由於錯誤報告 ,glibc對UINT8_C
的定義在2006年發生了變化。 之前的定義是#define UINT8_C(c) c ## U
,但是由於整數提升規則,在-1 < UINT8_C(0)
上產生了錯誤的輸出( false
)。
這三個定義是否都符合標准? 這三種實現之間是否存在其他差異(除負處理常量的處理之外)?
如果int
可以表示uint_least8_t
所有值,那么UINT8_C(value)
宏的GNU實現為#define UINT8_C(c) c
符合C標准。
根據C11 7.20.4宏對於整數常量第2段:
這些宏的任何實例中的參數都應是未填充的整數常量(如6.4.4.1中所定義),其值不超過相應類型的限制。
例如,如果UINT_LEAST8_MAX
為255,則以下用法示例是合法的:
UINT8_C(0)
UINT8_C(255)
UINT8_C(0377)
UINT8_C(0xff)
但是以下用法示例會導致未定義的行為 :
UINT8_C(-1)
- 不是6.4.4.1中定義的整數常量 UINT8_C(1u)
- 不是非整數常量 UINT8_C(256)
- 超出了此實現的uint_least8_t
的限制 由於相同的原因,帶符號的等效INT8_C(-1)
也是未定義的行為 。
如果UINT_LEAST8_MAX
為255,則UINT8_C(value)
的合法實例將擴展為整數常量表達式,並且由於整數提升,其類型將為int
,如第3段所述:
其中一個宏的每次調用都應擴展為適合在
#if
預處理指令中使用的整數常量表達式。 表達式的類型應與根據整數提升轉換的相應類型的表達式具有相同的類型。 表達式的值應該是參數的值。
因此,對於UINT8_C(value)
任何合法調用,通過int
可以表示uint_least8_t
所有value
的任何實現將其擴展為值是完全符合標准的。 對於任何非法調用UINT8_C(value)
,由於未定義的行為,您可能無法得到您期望的結果。
[EDIT為完整性添加]正如cpplearner的回答所指出的,OP問題中顯示的UINT8_C(value)
的其他實現是無效的,因為它們擴展為不適合在#if
處理指令中使用的表達式。
前兩個實現不符合C標准,因為它們不允許#if
指令中的UINT8_C(42)
:
#if UINT8_C(42) == 42 // <- should be a valid expression
其中一個宏的每次調用都應擴展為適合在
#if
預處理指令中使用的整數常量表達式。 表達式的類型應與根據整數提升轉換的相應類型的表達式具有相同的類型。 表達式的值應該是參數的值。
GNU C庫不正確。 Per C11 7.20.4.1最小寬度整數常量的宏 UINTN_C(value)
定義為
宏
UINTN_C(value)
將擴展為對應於類型uint_leastN_t
的整數常量表達式。
所以他們只是使用c
是uint_least8_t
因為c
可能是也可能不是uint_least8_t
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.