如问题所述,假设 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 为这种情况添加了一条规则,允许引发实现定义的信号。我不知道有任何编译器会这样做。)