这里通过例子来帮助理解整型提升和截断的规则。
问题:
- 赋值过程是怎样的?什么情况会发生截断?
- 整型提升的规则是什么? 根据什么类型来提升?
- %d, %u对整型提升后的结果有什么影响?
例一
#include <stdio.h>
int main()
{
char a = -128;
printf("%d\n", a);
printf("%u\n", a);
return 0;
}
运行这段代码的结果如下:
char如果不加unsigned默认是有符号类型。
为什么会出现两种不同的结果?
分析:
- -128是一个4字节整型,在内存中存储它的补码。
原码
1000 0000 0000 0000 0000 0000 1000 0000
反码(符号位不变,其余取反)
1111 1111 1111 1111 1111 1111 0111 1111
补码 (反码+1)
1111 1111 1111 1111 1111 1111 1000 0000 - char a = -128;
这一步发生截断,将-128的补码后8位赋给a
1111 1111 1111 1111 1111 1111 1000 0000 - 以%d打印的是有符号数:
这一步将会发生整型提升,提升规则:如果a是有符号数,将a的高位识别为符号位,按照符号位提升到32位。
a是 1000 0000
提升后 1111 1111 1111 1111 1111 1111 1000 0000
%d以有符号识别1111 1111 1111 1111 1111 1111 1000 0000,将被识别成补码形式。所以打印结果就是-128。 - 以%u打印的是无符号数:
这里会发生整型提升, 提升规则:如果a是有符号数,将a的高位识别为符号位,按照符号位提升到32位。
a是 1000 0000
提升后 1111 1111 1111 1111 1111 1111 1000 0000
%u以无符号数识别1111 1111 1111 1111 1111 1111 1000 0000,将被识别成原码形式,打印结果就是4294967168。
例二
#include <stdio.h>
int main()
{
unsigned char a = -1;
printf("%d\n", a);
printf("%u\n", a);
return 0;
}
结果:
分析:
- -1的原码、反码、补码:
1000 0000 0000 0000 0000 0000 0000 0001
1111 1111 1111 1111 1111 1111 1111 1110
1111 1111 1111 1111 1111 1111 1111 1111 - unsigned char a = -1;
发生截断:
1111 1111 1111 1111 1111 1111 1111 1111
a 为1111 1111 - %d以有符号类型识别整型提升后的"补码":
由于a是无符号数,整型提升在前面补0即可,没有符号位,不看符号位。
提升后:0000 0000 0000 0000 0000 0000 1111 1111
提升后的a识别为补码,因此结果是255 - %u以无符号数识别整型提升后的"原码":
由于a是无符号数,整型提升在前面补0即可,没有符号位,不看符号位。
提升后:0000 0000 0000 0000 0000 0000 1111 1111
将提升后的a识别为原码,打印结果就是255