在C语言中,signed要求最高位是符号位,以下表示数据大小,而unsigned则全部位都表示大小。如果用8位二进制表示的话,signed范围就是-128到127,unsigned就是
0到255,C语言中专门用两个关键字来描述两种表示方法,于是,就产生了一些不可思议的问题。
1、溢出
在有符号运算中可能会产生溢出问题,归纳起来就是:两个整数相加可能会溢出,两个负数相加也可能会溢出,一正一负相加肯定不会溢出。在《C深度剖析》中看到一个有趣的问题。
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[1000];
int k = 0;
for (; k < 1000; k++) {
a[i] = -1-i;
}
printf("%d\n", strlen(a));
return 0;
}
最终的结果是255。因为数组a[1000]是char类型的,在C语言中明确规定char类型占一个字节内存空间,且在x86的gcc平台上char默认是signed,一开始,k=0,a[0]=-1,随着k不断增大,当k=127,则a[127]=-128,对应的二进制是10000000,我们知道-128是编译器能表示的最小值,当k=128,a[128]当然不可能存储-129这个值了,因为最高位发生了溢出,所以在计算机中储存的补码值是01111111,。随着k继续增大,当k=254时,a[254]在计算机中存放的补码是00000001,而k=255,a[255]对应的存储值是00000000,即0,strlen函数遇到第一个0就停止,所有最后的结果是k从0到254,总共长度是255。
2、signed和unsigned混合运算
C语言中除了char类型,编译器默认其他整型都是signed,在x86的gcc平台上包括char在内所有整型都是signed。
#include <stdio.h>
int main(void)
{
unsigned a = 10;
unsigned b = -10;
if (a) printf("yes\n"); else printf("no\n");
if (b) printf("yes\n"); else printf("no\n");
int c = b;
printf("%d\n", c);
if (c) printf("yes\n"); else printf("no\n");
int d = -20;
int e = a + d;
printf("%d\n", e);
if (e) printf("yes\n"); else printf("no\n");
return 0;
}
最后结果是
yes
yes
-10
yes
-10
yes
从上面例子可以看出,在C语言中,有符号数可以赋值给无符号数,结果是一个无符号数,而无符号数也可以赋值给有符号数,结果还是一个无符号数;在混合运算中,只要有一个无符号数,都会将有符号数转化成无符号数参加运算,结果也以无符号保存。