先看一个奇怪的现象:

#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;
}