我们都知道,数据在计算机中是以二进制数存取的。任何数到了计算机底层都会被计算机转换为0,1.那么,负数在计算机是如何存取的呢?负号是没有办法存进计算机的。怎么办呢?做一个标记就好了。我们把数据的最高位腾出来,用来标记数据的符号。规定如下:若最高位为1,则为负数,其值为除最高位之外剩余位的值再加上一个负号,若最高位为0,则为正数,其值为除最高位之外剩余位的值。
这样,一个32位的signed int 类型的数,其值表示的范围为:-2^31~(2^31)-1。
8位的signed char 类型的数,其值表示的范围为:-2^7~(2^7-)1。
一个unsigned int 类型的数,其值表示的范围为:0~(2^32)-1。
一个unsigned char类型的数,其值表示的范围为:0~(2^8)-1。
接下来,我们看一下这个程序:
实例一:
<span style="font-size:12px;">#include<stdio.h>
#include<string.h>
int main()
{
int i = 0;
signed char arry[1000];
for (i = 0; i < 1000;i++)
{
arry[i] = -i - 1;
}
printf("%d ", strlen(arry));
system("pause");
return 0;
}</span>
这个程序看起来简单,实际上很多人都会做错。我们运行一下看一下结果:
是不是很惊讶?接下来我们分析一下程序。第一次循环时,arry[0]=-1。我们知道数据在计算机是以补码的形式存储的,正数的补码是其原码,负数的补码的求取方式是:符号位不变,其余位取反,然后加1。
我们来求一下-1的补码,假定计算机为32位。那么
-1就是: 10000000 00000000 00000000 00000001
取反后为:11111111 1111111 11111111 11111110
加1: 11111111 11111111 11111111 11111111
char 类型的大小为8个字节,所以-1的补码为0xff。arry[1]=-2,-2的补码为oxfe。一直循环下去,直到arry[127]=-128。我们知道,signed char 所能存取值得范围为:-128~127。所以循环到arry[128]时,arry[128]的值肯定不是-129,这时已经溢出了。
-129的表示:10000000 00000000 00000000 10000001
取反后为: 11111111 11111111 11111111 01111110
加1: 11111111 11111111 11111111 01111111
char 类型数据只有8位,而-129需要9位才能存储下来,所以最高位被丢弃,-129的补码是0x7f。
当i 继续增加到255时,-256的补码的低8位是0.
-256在内存中的补码如下:
-256的表示:10000000 00000000 00000001 00000000
取反后: 11111111 11111111 11111110 11111111
加1: 11111111 11111111 11111111 00000000
然后当i增加到256时,-257的补码的低8全为1。
-257的表示:10000000 00000000 00000001 00000001
取反后: 11111111 11111111 11111110 11111110
<span style="font-size:12px;">#include<stdio.h>
int main()
{
int i = -20;
unsigned j = 10;
printf("%d ", i + j);
system("pause");
return 0;
}</span>
结果如下:
<span style="font-size:12px;">#include<stdio.h>
int main()
{
unsigned i;
for (i = 0; i >= 0; i--)
{
printf("%u\n ", i);
}
system("pause");
return 0;
}</span>
结果如下: