测试过程中发现了数据相加超过类型范围的问题,以为是测试bug,查找资料才知道是运算过程中数据被整数提升了,这里一起学习总结一下整数提升和整型转换规则中的有符号数转换为无符号数。
1 整数提升
C99标准中有明确提到整数提升的概念:"如果int能够表示原始类型中的所有数值,那么这个数值就被转成int型,否则,它被转成unsigned int型。这种规则被称为整型提升。所有其它类型都不会被整型提升改变。"
为什么会有整数提升?这是因为对于int类型数据作运算时,CPU运算速度是最快的,所以C语言会对数据作整数提升的处理,使得程序的运行速度尽可能地快。
C语言中基本整型数据的类型范围:
signed char: -127 -> 127
unsigned char: 0 -> 255
signed short: -32767 -> 32767
unsigned short: 0 -> 65535
signed int: -2147483647 -> 2147483647
可以看出,char/uchar,short/ushort都可以被int表示。所以当它们做算术运算时,都会被提升成int类型。
(unsigned的类型转换成int类型,高位补0。)
例如:
int main()
{
char a=127;
unsigned char b=255;
short c=32767;
unsigned short d=65535;
printf("char: a+1=%d %d\n",a+1,sizeof(a+1));
printf("uchar: b+1=%d %d\n",b+1,sizeof(b+1));
printf("short: c+1=%d %d\n",c+1,sizeof(c+1));
printf("ushort: d+1=%d %d\n",d+1,sizeof(d+1));
return 0;
}
结果:
char: a+1=128 4
uchar: b+1=256 4
short: c+1=32768 4
ushort: d+1=65536 4
C语言中有符号数和无符号数进行运算(包括逻辑运算和算术运算)默认会将有符号数看成无符号数进行运算。也就是说,int/long和对应类型的unsigned int/unsigned int进行运算时,有符号数会自动转换为对应类型的无符号数。对这几种数据,无符号的优先级要比有符号数要高。
注意:这种转换规则不适用于char/uchar,short/ushort类型,因为这些类型会存在整数提升
例1:逻辑运算
有符号数和无符号数比较大小
int main()
{
int a=-1;
unsigned int b=2;
long c=-1;
unsigned long d=2;
if((a>b)&(c>d))
{
printf("-1>2");
}
return 0;
}
结果:
-1>2
可以看到,-1居然比2大,这是因为因为a和b(c和d)进行比较的时候,有符号数-1(0xFFFFFFFF)被当做无符号数2和进行比较。
例2:算术运算
有符号数和无符号相加
int main()
{
int a=2147483647;
unsigned int b=1;
printf("a+b=%d\n",a+b);
printf("a+b=%u\n",a+b);
printf("%d\n",2147483648);
return 0;
}
结果:
a+b=-2147483648
a+b=2147483648
-2147483648
可以发现,相加的结果并不会受影响。这是因为int和unsigned int在内存中都是4个字节,即使有符号数被看做无符号数参与计算,也不会影响算术运算的最后结果。