数学上的数字,是没有限制的,可以无限大,而在计算机中,受硬件的制约,数据是有长度的(即每个数据最多可以有几个二进制位),称为数据宽度,超过最大宽度的数据将会丢失一部分。我们知道计算机数据表示只能有0,1两个数字,称为二进制,那么在程序编程语言中,我们一般划分数据宽度为三种:
BYTE 字节 8 bit
WORD 字 16bit 字=2字节
DWORD 双字 32bit 双字=2字=4字节
以C语言为例,char 数据宽度为byte,short 数据宽度为word,int数据宽度为dword。
我们分析一下在计算机中数据宽度是如何理解的。
下面我们逐一分析
以4位宽度为例,假设计算机只能存储4个二进制位。2^4=16,可以存储16个数字,
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100
1101 1110 1111
若这16个数
全是无符号数:
0 1 2 3 4 5 6 7 8 9 A B C D E F
全是有符号数:
正数: 0 1 2 3 4 5 6 7
负数: -1 -2 -3 -4 -5 -6 -7 -8
F E D C B A 9 8
由上面分析,我们可以看出,计算机中存储的只是若干位的二进制数,计算机并不区分正负数,正负数是编程人员规定的。从示意图可以看出,F为最大负数,因为F再进一位就为0,所以F 是最大的负数,而且从有符号数说起,纵轴左边是负数,最高位为符号位,最高位为1就是负数,为0就是正数。这也可以理解计算机中存储负数,即存储该数绝对值的补码,然后最高位变为1 ,即可。
切记,计算机并不决定数是正数还是负数,正负性是由编程人员决定的,从原理上看,无论整数还是负数,在计算机中表示的二进制字符串都相同,由编程人员来确定正负。
比如 8位的二进制数 10000000,若为无符号数,则是128,若是有符号数,则是-128,由此可见,正负性是由编程人员决定的。
同理以8位宽度为例,即以字节byte为例,可以得到示意图,4位二进制用16进制表示
无符号数:
0 1 2 3 … FF(10进制为255)
有符号数:
正数: 0 1 2 … 7F(10进制127)
负数: -1 -2 -3 … -128
FF FE FD … 80
同理 16位宽度,假设计算机只能存储16位二进制位
无符号数:
0 1 2 3 … FFFF(10进制为2^16-1)
有符号数:
正数: 0 1 2 … 7FFF(10进制127)
负数: -1 -2 -3 -4 …
FFFF FFFE FFFD FFFC …
同理 32位宽度,不在此罗列了
总结:
从计算机角度看,它不知道什么叫有符号数,什么叫无符号数,什么是正数,什么是负数,只管存储二进制数,但是从使用者角度看,计算机中每个数据都是一个容器,有自己最大的宽度,可以决定是否有无符号(从而数据宽度也不同),一旦超过宽度,将会使得最高位数据被丢失。
学以致用:
分析下面C语言程序,写出程序运行结果(此题摘自程正冲的C语言深度剖析)
Int main()
{
char a[1000];
int i;
for(i=0;i<1000;i++)
{
a[i]=-1-I;
}
printf(“%d”,strlen(a));
return 0;
}
思路:越是简单题越容易出错,很多同学看到strlen函数,哦求字符串长度,直接写个1000,
而有的同学可能会进一步思考,求字符串长度函数的本质是什么,是遇到第一个数字0的时候就输出长度,可是困惑字符数组a的哪个下标存储数组0。这里就要用到我们刚才所讲的数据宽度问题。因为数组a为字符型,宽度为一个byte,而分析for循环可知,
a[0]=-1,计算机存储的是0xff,
a[1]=-2,计算机存储0xfe,
…
a[127]=-128,是char类型所能存储的最小负数0x80。
当i在增1 时,a[128]的值肯定不是-129,因为一个byte字节能存储的有符号数为-128~ ~127,因此会发生下溢,最高位被丢弃,剩下的8位是0111 1111 ,即0x7f,(原因如下
(1000 0000)-(0000 0001)=(0111 1111),向第九位借了一位
)
I继续增大,直到a[254]=0x1,a[255]=0x0,
然后a[256]=0xff,又开始循环,但是a[255]=0即0000 0000,因此可以肯定a[0]到a[254]都不为0,而a[255]为0,所以strlen(a)长度是255.
解法二:如果是选择题,也可以简略思考答案,首先依据示意图无符号数(范围从0到255共256个数)就可以得出,从a[0]=0xff,一直减1,就是绕示意圆顺时针转,一直转到a[255]=0x00,所以strlen(a)长度为255.