概念
在C语言中,整数类型按照其大小可以分为以下几类(从小到大):
char
short
int
long
long long
当在表达式中涉及这些类型的混合运算时,较小的类型会被提升为较大的类型。具体规则如下:
①char
和 short
在大多数情况下会被提升为 int
。
②如果 int
可以表示 char
或 short
的所有值,则 char
和 short
会被提升为 int
。
③如果 int
不能表示 char
或 short
的所有值(这种情况很少见,通常只在某些特殊硬件上发生),则 char
和 short
会被提升为 unsigned int
。
④int
和 unsigned int
在运算时不会被提升为更大的类型,除非与更大的类型(如 long
)混合使用。
⑤long
和 unsigned long
在运算时通常不会被提升为 long long
,除非与 long long
混合使用。
示例
来看这样的一段代码来了解这个机制的具体作用:
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t arr[4];
uint8_t arr1[4];
arr[0] = 0x00;
int8_t x=~arr[0];
if(x==~arr[0])
{
printf("int8_t x=%d\n", x);
}else{}
arr1[0] = 0x00;
uint8_t y = ~arr1[0];
if (y==~arr1[0])
{
printf("Hello World\n");
}else{}
return 0;
}
编译运行的输出结果为:
仅仅输出了第一个if语句内的内容,原因是什么呢?可以试着把第二个if语句内要输出的内容改成“hello world”试试,结果依然是只输出了第一个,初步推测是第二个if语句内的条件不为真导致的。
调试
按下F10开始调试,点击调试->窗口->监视;
然后设置三个观察条件,分别是arr1[0]、y以及~arr1[0];
在最后一个空的else代码块打断点,并且运行到它的if语句那一行;
可以看到和Keil一样,有断点(程序暂停)和箭头的UI(程序当前运行停止的位置)。
从监视栏也可以看到~arr1[0]的类型从unsigned char类型被提升为了int型,并且此时y=255不等于~arr1[0]。
我们再直接输出结果看看:
可以看到如果强行及将~arr[0]作为unsigned char类型输出,结果是0xFFFFFFFF。
注意数据在一切计算机(单片机、Soc、PC等)中的存储形式都是补码,Visual Stdio中我们选择了32位的数据处理位宽那么此时~arr[0]的实际内容就是1111 11111 1111 1111 1111 1111 1111 1111。
更改一下占位符:
作为int类型输出,结果就是-1(-1的补码是32个1)。
注意
C语言的强弱类型之争到今天也没结束,类型提升导致的bug是可以通过良好的编码习惯避免的,我们在日常编程的过程中要尽量避免不同类型的数据之间进行数值比较。