原码,反码,补码, 大小端

原码, 反码, 补码 详解

机器数与真值

  1. 机器数

    • 一个数在计算机中的二进制表示形式, 叫做这个数的机器数;
    • 机器数是带符号的, 使用最高位为符号位, 正数为0, 负数为1;
    • 如: +3:0000 0011; -3:1000 0011; 这里的二进制就是机器数;
  2. 真值

    • 因为第一位为符号位, 所以机器数的形式值就不等于真正的数值;
    • 如:1000 0011, 其最高位1代表负, 其真正数值是-3而不是形式值131;
    • 将符号位的机器数对应的真正的数值称为机器数的真值;
    • 如: 0000 0001的真值是: +1; 1000 0001的真值是: -1;

==原码, 反码, 补码的基础概念和计算方法==

  1. 原码

    • 原码就是符号位加上真值的绝对值
    • 第一位为符号位,所以8位二进制的范围为: [1111 111, 0111 111]; [-127, 127]
    • 上面的范围缺-128? 后面解释.
    • 最符合人脑的方式;
  2. 反码

    • 正数的反码是其本身;
    • 负数的反码是在其反码的基础上, 符号位不变, 其余位取反:如

      • [+1] = [0000 0001]原 = [0000 0001]反
      • [-1] = [1000 0001]原 = [1111 1110]反
    • 如果一个反码表示负数, 人脑无法直接观看;

  3. 补码

    • 正数的补码是其本身;
    • 负数是其反码+1, 如下:

      • [+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
      • [-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补

        使用原码,反码,补码的原因

  4. 对于正数都是一样的,所以忽略;

  5. 对于负数,不同, 为什么会存在呢?

    • 对于人脑, 可以知道第一位是符号位, 在计算的时候会根据符号位,选择对真值区域的加减;
    • 对于计算机,加减乘除已经是最基础的运算, 要设计的尽量简单, 计算机辨别”符号位”显然会让基础电路 变的复杂, 于是人们开始考虑让符号位也参与运算的方法;
    • 根据运算规则, 1-1 = 1 + (-1) = 0; 如果机器只有加法没有减法, 计算机运算的设计就更简单了;
    • 人们继续探索将符号位参与运算, 并且只保留加法的方法:

      • 1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [1000 0010]原 = -2 如果用原码表示,让符号位参与运算, 显然对于减法来说, 结果不正确, 这也就是计算机中不使用 原码表示一个数, 为了解决原码做减法的问题, 出现了反码;
      • 1 - 1 = 1 + (-1) = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0 发现使用反码计算减法, 结果的真值部分是正确的, 但是确出现了-0, 而且-0是没有用, 并且会有 [0000 0000]原 和 [1000 0000]原 俩个编码表示0; 于是出现了补码, 解决了0的符号问题, 以及俩个编码的问题,
      • 1-1 = 1 + (-1) = [0000 0001]补+[1111 1111]补 = [0000 0000]补 = 0 (-1)+(-127) = [1111 1111]补 + [1000 0001]补 = [1000 0000]补 = -128; -1-127的结果是-128, 在用补码运算的结果中, [1000 0000]补 就是-128, 实际就是-0的补码, 所以-128并没有原码和反码表示.
    • 使用补码, 不仅仅修复了0的符号以及存在俩个编码的问题, 而且还能够多表示一个最低数, 这就是为什么8位二进制, 使用原码或反码表示的范围是[-127, 127], 而使用补码表示的范围是[-128, 127];

    • 机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围: [-2^31, 2^31 -1], 因为第一位表示符号位,使用补码表示时可以多保存一个最小值;

原码,反码, 补码 再深入

参考网址:博客园已转载

大端小端

  • 小端: 低位字节存放在内存的低地址端, 高位字节存放在内存的高地址端;
  • 大端: 高位字节存放在内存的低地址端, 低位字节存放在内存的低地址端;
  • 网络字节序: 大端模式;
1
2
3
4
5
6
7
8
9
10
11
如:
十进制: 10 000
二进制: 100111 00010000
十六进制: 0x27 0x10

大端机制存储:
00100111 00010000
0x27 0x10
小端机制存储:
00010000 001000111
0x10 0x27
1
2
3
4
5
6
7
8
9
10
11
// 算法
union {
unsigned int a;
unsigned char b;
}c;
c.a = 1;
if (1 == c.b) {
printf("小端序");
} else {
printf("大端序");
}