5——原码,反码,补码,大端模式与小端模式



码制

我们首先要知道,一个10进制的整数要在以2进制为基础的内存中储存,那么就必须有一定的规则,不能以我们日常的书写方式储存。这样的规则有几种,分别是原码,反码,补码三种码制。接下来我们分别讨论。

原码

原码很好理解,就是把一个整数转换为二进制,比如单字节的5的源码就是0000,0101。这是无符号数的表示方式,如果遇到有符号数,我们肯定是不能说加个“-”负号搞定的,因为二进制中没有负号这玩意,因此我们将第一位作为表示正负的标志位,规定0表示正数,1表示负数。如Figure1所示。因此-5的原码是1000,0101

5——原码,反码,补码,大端模式与小端模式_第1张图片

Figure 1

这样其实会出现一个问题,那就是会出现0000,0000和1000,0000都表示零的问题,其中一个是“正零”一个是“负零”,但我们都知道零就是零哪有两个,因此我们的计算机并不采用原码表示数。


反码

         反码这个概念也很直接,正数的反码就是原码自己,负数的反码就是将原码中除了符号位之外的每一个位取反,例如单字节的5的反码是0000,0101,-5的反码为1 111,1010。

         这样处理之后,“正零”的反码就变成了0000,0000,“负零”的反码就变成了1111,1111,好吧,现在还是零有两个表示,这样还是不符合计算机的要求。


补码

以上的两种码制都不符合要求,那么我们又要提出一种码制,那就是补码,正数的补码就是其原码,负数的补码是其反码加上1,比如单字节的5的补码为0000,0101,而-5的补码为1111,1011。

         大家注意看零的变化,这个时候“正零”的补码就变成了0000,0000,“负零”的补码就变成了1111,1111+1 = 1,0000,0000。大家要注意到,单字节只有八位,也就是说加一进位得到的1是会溢出的,因此在计算机眼中单字节的1111,1111+1 = 0000,0000。

这样子就实现了“正零”和“负零”的大一统,皆大欢喜皆大欢喜。因此在计算机内存中,数值一律采用补码表示 而且,采用补码还有一个巨大的好处,那就是可以把减法化为加法运算,我们举个例子。 例如:16-9 = 16+(-9),16的补码为0001,0000,-9的补码为1111,0111两个补码相加得到1111,0111+0001,0000=1,0000,0111 把溢出的高位1去掉得到了0000,0111也就是7,和16-9的结果相同。

         给个例子,Figure2中前者是-1在计算机中的储存方式,后者是1在计算机中储存的方式,其中负数采用补码,正数采用的补码其实就是和原码一样的。


Figure 2

大端模式,小端模式

我们上一节讨论了码制,现在我们讨论下大小端系统。首先大小端系统一共有两个:大端系统(Big endian)和小端系统(Little endian)。为什么要有这两个概念呢?我们看一下下面的这个程序的结果。

int var =0x01020304;

int *ptr_var=&var;

Figure 3

由Figure3可以看出var变量的地址为0x0040fd1c,那么我们看看内存里这个地址的值怎么表示的。如Figure4所示。


Figure 4

看到没有,内存中0x01020304中的高字节0x01对应高地址0x0040fd1f,低字节0x04对应低地址0x0040fd1c,因此这种高字节对应高地址,低字节对应低地址的方式称之为小端模式。与此对应的有大端模式,也就是高字节对应低地址,低字节对应高地址的方式,其效果如Figure5所示。

Figure 5
搞清楚大小端是有必要的,因为不同计算机系统可能采用不同的模式,如果不进行预先的变换,那么有些程序就没法移植或者计算机之间没法通信。




你可能感兴趣的:(C/C++)