整数提升如何在 C Cast 上工作?
How does integer promotion work on C Cast?
我被意外的整数提升所困扰,这让我感到奇怪。 是否在显式转换之前进行提升是否在编译器之间保持一致?
让我解释一下。有一个带符号的 8 位变量,例如
int8_t s8a = -128; //<-- 0x80
将无符号 16 分配为 uint16_t s16b = s8a + 1;
我希望提升为更大的整数 0xFF81
然后分配,这是一个常见的错误,并且在 MISRA C 等文档中考虑过。但是显式转换以 uint16_t s16b = (uint16_t)s8a
之类的方式转换为无符号类型我希望 s8a
立即丢失其 "signedness" 然后零扩展到 16 位以给出 0x0080
但实际上相反发生了,因为它得到符号扩展 然后 在铸造和赋值时失去其符号性 0xFF80
.
这是标准行为还是 C 的另一个未定义行为?
这与整数提升无关,而是与类型转换有关。在您的情况下,该过程由 C11 Standard - 6.3.1.3 Signed and unsigned integers (p2):
明确定义
.. if the new type is unsigned, the value is converted by repeatedly
adding or subtracting one more than the maximum value that can be
represented in the new type until the value is in the range of the new
type.
所以这里 0xFF80 = 0xFFFF + (-128) + 1
,因为 0xFFFF
是 uint16_t
中可以表示的最大值。
给定初始化int8_t s8a = -128;
:
- 在初始化的情况下
uint16_t s16b = s8a + 1;
:
- 在表达式
s8a + 1
中,s8a
((int8_t)-128
)中的值被提升为(int)-128
并加上(int)1
得到(int)-127
.
- 在初始化
uint16_t s16b = (int)-127;
时,将(int)-127
转换为(uint16_t)0xff81
存入s16b
。
- 在初始化的情况下
uint16_t s16b = (uint16_t)s8a + 1;
:
- 在表达式
(uint16_t)s8a
中,s8a
((int8_t)-128
)中的值被转换为(uint16_t)0xff80
.
- 在表达式
(uint16_t)0xff80 + 1
中:
- 如果
INT_MAX >= 65535
,则(uint16_t)0xff80
转换为(int)0xff80
并加上(int)1
得到(int)0xff81
.
- 如果
INT_MAX < 65535
,则1
转换为(uint16_t)1
加上(uint16_t)0xff80
得到(uint16_t)0xff81
.
- 在初始化
uint16_t s16b = (int)0xff81;
(当INT_MAX >= 65535
),或初始化uint16_t s16b = (uint16_t)0xff81;
(当INT_MAX < 65535
):
- 如果
INT_MAX >= 65535
,则(int)0xff81
转换为(uint16_t)0xff81
,存入s16b
。
- 如果
INT_MAX < 65535
,则(uint16_t)0xff81
存储在s16b
。
在这两种情况下,s16b
都被初始化为值 (uint16_t)0xff81
。
我被意外的整数提升所困扰,这让我感到奇怪。 是否在显式转换之前进行提升是否在编译器之间保持一致?
让我解释一下。有一个带符号的 8 位变量,例如
int8_t s8a = -128; //<-- 0x80
将无符号 16 分配为 uint16_t s16b = s8a + 1;
我希望提升为更大的整数 0xFF81
然后分配,这是一个常见的错误,并且在 MISRA C 等文档中考虑过。但是显式转换以 uint16_t s16b = (uint16_t)s8a
之类的方式转换为无符号类型我希望 s8a
立即丢失其 "signedness" 然后零扩展到 16 位以给出 0x0080
但实际上相反发生了,因为它得到符号扩展 然后 在铸造和赋值时失去其符号性 0xFF80
.
这是标准行为还是 C 的另一个未定义行为?
这与整数提升无关,而是与类型转换有关。在您的情况下,该过程由 C11 Standard - 6.3.1.3 Signed and unsigned integers (p2):
明确定义.. if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
所以这里 0xFF80 = 0xFFFF + (-128) + 1
,因为 0xFFFF
是 uint16_t
中可以表示的最大值。
给定初始化int8_t s8a = -128;
:
- 在初始化的情况下
uint16_t s16b = s8a + 1;
:- 在表达式
s8a + 1
中,s8a
((int8_t)-128
)中的值被提升为(int)-128
并加上(int)1
得到(int)-127
. - 在初始化
uint16_t s16b = (int)-127;
时,将(int)-127
转换为(uint16_t)0xff81
存入s16b
。
- 在表达式
- 在初始化的情况下
uint16_t s16b = (uint16_t)s8a + 1;
:- 在表达式
(uint16_t)s8a
中,s8a
((int8_t)-128
)中的值被转换为(uint16_t)0xff80
. - 在表达式
(uint16_t)0xff80 + 1
中:- 如果
INT_MAX >= 65535
,则(uint16_t)0xff80
转换为(int)0xff80
并加上(int)1
得到(int)0xff81
. - 如果
INT_MAX < 65535
,则1
转换为(uint16_t)1
加上(uint16_t)0xff80
得到(uint16_t)0xff81
.
- 如果
- 在初始化
uint16_t s16b = (int)0xff81;
(当INT_MAX >= 65535
),或初始化uint16_t s16b = (uint16_t)0xff81;
(当INT_MAX < 65535
):- 如果
INT_MAX >= 65535
,则(int)0xff81
转换为(uint16_t)0xff81
,存入s16b
。 - 如果
INT_MAX < 65535
,则(uint16_t)0xff81
存储在s16b
。
- 如果
- 在表达式
在这两种情况下,s16b
都被初始化为值 (uint16_t)0xff81
。