由于整形在内存中拥有不同的类型,当把一个字节较长的整形数值赋给一个字节较短的整形变量会出现整形截断,而当将一个字节较短的整形变量用一个字节较长的整形变量输出时则会出现整形提升。在表达式计算时,各种整形首先要提升为int类型,如果int类型不足以表示则要提升为unsigned int类型,然后执行表达式的运算。
下面以几个简短的代码来说明问题:
一、
#include <stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d, b=%d, c=%d", a, b, c);
return 0;
}
在vs编译环境下认为char
为有符号的,所以a、b的输出结果相同。
-1在内存中的存储是按其二进制补码存放,格式如下:
11111111 11111111 11111111 11111111
又因为在vs编译环境下数据是按照小端存放的,所以char
中只存放了-1的低八位二进制数字
11111111
而后面的打印格式却要求以整形输出,则进行整形提升有符号位补符号位,无符号位补0
,所以a、b补全后还原为
11111111 11111111 11111111 11111111
即输出-1
而c在补全的时候无符号位,补0
00000000 00000000 00000000 11111111
则c输出255
二、
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
-128在内存中的存放格式
11111111 11111111 11111111 10000000
放入char中的格式
10000000
以%u格式(无符号数格式)打印,但因char为有符号数,补全后还原为为
11111111 11111111 11111111 10000000
此时将此数当成无符号数,输出为
当然由于128在内存中的存放格式为
00000000 00000000 00000000 10000000
以上面的代码输出会出现同样的结果。
三、
当在循环的判断部分出现无符号数,则循环极有可能陷入死循环。
#include <stdio.h>
int main()
{
unsigned int i;
for (i=9; i>=0; i--)
{
printf("%u\n",i);
}
return 0;
}
当i从0降到-1时,存放格式为
11111111 11111111 11111111 11111111
但是编译器将此数当成无符号数(即2^33-1)为了便于观察,将输出格式定位%u,可以直观看到一个非常大的数字迅速递减的变化。
#include <stdio.h>
int main()
{
unsigned char i = 0;
for (i=0; i<=255; i++)
{
printf("hehe\n");
}
return 0;
}
当i加到256时存放格式为
00000000 00000000 00000001 00000000
截断放到无符号位的char中仍为0,累加继续,故陷入死循环。
四、
#include <stdio.h>
#include <string.h>
int main()
{
char a[1000];
int i;
for (i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d\n", strlen(a));
return 0;
}
因为char的表数范围是-128~127
i从0加到127,a[i]从-1减到-128
-128再减1为-129,其存放格式为
11111111 11111111 11111111 01111111
截断后放入char中为
01111111
因其有符号位,则此数为127
i再从128加到255,a[i]从127减到0
而0前面的数字个数为255