C语言截断与整型提升
先看一个奇怪的现象:
#include <stdio.h>
int main()
{
int a = 453;
char c;
c = a;
printf("%d\n", c);
return 0;
}
运行上面的代码,结果如下:
为什么453输出变成了-59呢?
这就涉及到了C语言中的截断和整型提升。
截断
在c语言中进行变量赋值的时候,如果
将字节多的数据类型赋给一个占字节少的变量类型
,会发生“截断”。发生这种情况的原因是:在赋值过程中只将占字节较长的变量的地位赋给占字节较少的变量。
我们都知道,int类型是32位(4字节),char类型是8位(1字节)
453在int类型中的存储格式如下:
在char类型中,由于char的存储空间不足4字节,所以只会存原int类型的低8位,存储格式如下:
到这儿你也许会说: 不对啊,‘11000101’是197,怎么看也不是(-59)啊?
这就和整型提升有关了
整型提升
整型提升是C程序设计语言中的一项规定:在表达式计算时,各种整形首先要
提升为int类型
,如果int类型不足以表示则要提升为unsigned int类型
;然后执行表达式的运算。
首先来看整型提升的规则
1.若是有符号数,则前面8*3位补符号位。
2.若是无符号数,则前面8*3位补0。
现在再来看,原来的char类型的c被提升成了int类型,因为这里是有符号char类型,所以11000101
中的第一位被解释为符号位,整型提升为
到这儿又有人会说不对了,别急,回忆一下负数在计算机中使怎么存储的
计算机存的是补码,负数的补码是反码+1
于是反码:
补码:
于是打印出来便是-59
。
无符号
若是换成无符号(unsigned char)型
结果如下图:
原理:
截断为11000101
无符号,整型提升补0
正数原码、反码、补码相同
于是最终存储的还是11000101
输出197
练习
int main()
{
char a = 0xb6; //1011 0110
short b = 0xb600; //1011 0110 0000 0000
int c = 0xb6000000;// 1011 0110 0000 0000 0000 0000 0000 0000
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
system("pause");
return 0;
}
// 会输出哪个字符呢?
解析
在x86架构上的Visual C++或gcc编译下,上述程序输出为 c 。这是因为在这些环境下,编译器把char定义为signed char(C语言标准没有规定char类型是有符号还是无符号);
表达式a == 0xb6被整型提升,其中char类型的a提升为int类型并为一个负值,因此这个表达式的结果为false;
表达式b == 0xb600被整型提升,其中short类型的b提升为int类型并为一个负值,因此这个表达式的结果为false;
表达式c == 0xb6000000没有做整型提升,== 运算符的两端都是int类型的负值,其结果为true。
C语言的单操作数的+运算符(即“前缀+”),一个主要作用就是实现对操作数的整型提升。例如:
int main()
{
char a = 1;
printf("%u\n", sizeof(a));
printf("%u\n", sizeof(+a));
system("pause");
return 0;
}