C中signed与unsigned
1 unsigned int i=3; 2 cout<<i * -1;
第一反应:-3。不过结果似乎不是这样的,写了个程序,运行了一下,发现是:4294967293。
0到255,C语言中专门用两个关键字来描述两种表示方法,于是,就产生了一些不可思议的问题。
1、溢出
在有符号运算中可能会产生溢出问题,归纳起来就是:两个整数相加可能会溢出,两个负数相加也可能会溢出,一正一负相加肯定不会溢出。在《C深度剖析》中看到一个有趣的问题。
1 #include <stdio.h> 2 #include <string.h> 3 int main(void) 4 { 5 char a[1000]; 6 int k = 0; 7 for (; k < 1000; k++) 8 { 9 a[i] = -1-i; 10 11 } 12 printf("%d\n", strlen(a)); 13 return 0; 14 }
最终的结果是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。
1 #include <stdio.h> 2 3 int main(void) 4 { 5 unsigned a = 10; 6 unsigned b = -10; 7 if (a) printf("yes\n"); else printf("no\n"); 8 if (b) printf("yes\n"); else printf("no\n"); 9 10 int c = b; 11 printf("%d\n", c); 12 if (c) printf("yes\n"); else printf("no\n"); 13 14 int d = -20; 15 int e = a + d; 16 printf("%d\n", e); 17 if (e) printf("yes\n"); else printf("no\n"); 18 19 return 0; 20 }
最后结果是
yes
yes
-10
yes
-10
yes
从上面例子可以看出,在C语言中,有符号数可以赋值给无符号数,结果是一个无符号数,而无符号数也可以赋值给有符号数,结果还是一个无符号数;在混合运算中,只要有一个无符号数,都会将有符号数转化成无符号数参加运算,结果也以无符号保存。
注意:signed 和 unsigned 在电脑中的存储形式是一样的,只是解释方法不同,即一个有符号,一个无符号。
%d打印的是signed类型的,而%u才是打印的unsignd类型的,用不同的打印相当于一个类型转换了。当然C++比较直观,能直接自动识别出类型并打印值。
就用上面的例子:
unsigned c = 3; printf("%d\n",(c*(-1))); // 打印出的是-3 printf("%u\n",(c*(-1))); // 打印出的是4294967293