如问题所述,假设 16-bitshort
和 32-bit int
。
unsigned short a = 0xFFFF;
这将初始化a
为0xFFFF
或65535
。表达式0xFFFF
的类型为int
; 它被隐式转换为unsigned short
,并保留该值。
signed short b = 0xFFFF;
这有点复杂。再次,0xFFFF
是类型int
。它被隐式转换为signed short
-- 但由于该值超出了signed short
转换范围,因此无法保留该值。
当值无法表示时,将整数转换为有符号整数类型会产生实现定义的值。原则上, 的值b
可以是介于两者之间的任何-32768
值+32767
。在实践中,几乎可以肯定-1
。我将假设其余部分的值为-1
.
unsigned int u16tou32 = a;
的值为 ,a
从0xFFFF
转换unsigned short
为unsigned int
。转换保留了价值。
unsigned int s16tou32 = b;
的b
值为-1
。它被转换为unsigned int
,显然无法存储 的值-1
。将整数转换为无符号整数类型(与转换为有符号类型不同)由语言定义;结果是减少模MAX + 1
,其中MAX
是无符号类型的最大值。在这种情况下,存储在中的值s16tou32
是UINT_MAX - 1
, 或0xFFFFFFFF
。
signed int u16tos32 = a;
a
, ,的值0xFFFF
转换为signed int
. 该值被保留。
signed int s16tos32 = b;
b
, ,的值-1
转换为signed int
. 该值被保留。
所以存储的值是:
a == 0xFFFF (65535)
b == -1 (not guaranteed, but very likely)
u16tou32 == 0xFFFF (65535)
s16tou32 == 0xFFFFFFFF (4294967295)
u16tos32 == 0xFFFF (65535)
s16tos32 == -1
总结一下整数转换规则:
如果目标类型可以表示该值,则保留该值。
否则,如果目标类型是无符号的,则取模MAX+1
,这相当于丢弃除低位 N 位之外的所有位。描述这一点的另一种方式是,该值MAX+1
被重复地添加到该值中或从该值中减去,直到您获得该范围内的结果(这实际上是 C 标准描述它的方式)。编译器实际上并不生成代码来执行这种重复的加法或减法。他们只需要得到正确的结果。
否则,目标类型是有符号的,不能表示值;转换产生一个实现定义的值。在几乎所有的实现中,结果使用二进制补码表示丢弃除低位 N 位之外的所有位。(C99 为这种情况添加了一条规则,允许引发实现定义的信号。我不知道有任何编译器会这样做。)