原、反、补码与大小端的详细讲解(第二期)

目录

1.原码、反码、补码

2.大小端介绍

3.百度2015年系统工程师笔试题


1.原码、反码、补码

    1.1  为什么先人们要创造出原码、反码、补码呢?  为什么?

       对于计算机,加减乘数已经是最基础的运算,要设计的尽量简单。计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法。我们知道,根据运算法则减去一个正数等于加上一个负数,即: 1-1 = 1 + (-1) = 0 ,所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单了。

   使用原码、反码、补码还有以下二个好处:

      1.在计算机系统中,数值一律用补码来表示存储。原因在于,使用补码,可以将符号位和数值域统一处理

       2.同时,加法和减法也可以统一进行处理(CPU只有加法器此外,补码和原码相互处理,其运算过程是相同的,不需要额外的硬件电路。

   1.2 介绍原码、反码、补码

        计算机中的整数有三种表示方法,即原码、反码和补码

        三种表示方法均分为符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位负整数的三种表示方法各不相同。

       下面就来以整数十进制 - 1来形象的表示原码、反码、补码:

(补充:因为int类型占4个字节,为32个比特位)

原码:10000000  00000000  00000000  00000001 直接二进制按照正负数的形式转化为2进制就行(当为负数情况下最高位代表符号位)

反码:11111111  11111111  11111111  11111110        将原码的符号位不变,其他位按位取反就行了

补码:11111111  11111111  11111111  11111111         反码 +1 = 补码

 注意:

        1.正数的原码,反码,补码都相同。

        2.对于整形来说:数据存放内存中其实存放的是补码。


2.大小端的介绍

        我们先来做一个实验看下面变量在编译器中内存是什么?

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    int a = 20;
    printf("%p\n", &a);
    int b = -10;
    printf("%p\n", &b);
    return 0;
}

       我们的思路是建立二个动态变量a,b 分别赋值一个正数和一个负数这样方便于我们更好的实验。然后我们用printf打印函数打印出二个变量在内存中的存储地址。(可能有些小伙伴不知道怎么在vs中来查找数据在内存的存储)

2.1如何用vs来查找数据在内存的存储?

      1.我们先对代码进行调试(注意是调试!按F11进行调试不是F5进行编译

      2.然后在最上面一栏中找到 调试 -> 窗口 -> 内存 ->  使用内存1,2,3,4。(注意没有内存这一栏的话,那肯定是你没有进行调试)

      3.在将我们打印的地址输入就行了,地址的右边列那栏可以更改你需要显示的列数,根据不同的列数会转换成不一样的进制。

2.2 什么是大小端?

      在上面我们介绍了如何在vs中来查找数据在内存的存储。下面我们就来介绍下什么是大小端。如图:

594fdb680d1e4fdea94955bed53ecbe8.png4542e529ee194a84a720a0a237d5efe2.png

       上面我们已经介绍了,在计算机中整形数据是以补码的形式进行存储我们先算出a与b的补码是多少

a:

原码:0000 0000 0000 0000 0000 0000 0001 0100

(因为正数原,反,补都相同)

即转换为16进制为:  00 00 00 14

b:

原码:1000 0000 0000 0000 0000 0000 0000 1010

反码:1111  1111  1111  1111  1111  1111 1111  0101

补码:1111  1111  1111  1111  1111  1111 1111  0110

即转换为16进制为: ff ff ff ff ff ff ff f6

       补充注意:在16进制中以每个数前面 ‘0’ 代表正数。‘f’ 代表负数。 

       我们可以看见对于a和b分别存储的是补码。但是我们发现顺序有点不对劲。

2.3 什么是大端小端

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

2.4 为什么有大端和小端

       为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。

       但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

       例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式, 刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

d7f034cc53294e75bc9c5bef3a065328.png


3.百度2015年系统工程师笔试

题目:请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

 代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
}

 思路:

         int i = 1;  //则变量i在内存中的地址为

252a053452f24131b062662d1bfa8111.png

        这里我们只需要判断第一个字节 01 是位于低地址还是高地址就可以判断出是大端还是小端了。但是我们怎么才可以取到第一个字节的内存呢?

        这里我们用char*的形式,我们将i变量地址转换为char*指针类型然后在引用就可以得到第一个字节的内存了。如图:

38ab1e0165b44d54aefacee34048de6d.png

 4aa408b4b7fe474e851aec5a293fbdb0.png

      如图,我们可以很清楚的看出来在函数中返回第一个字节的值,若为1的话就是小端,若为0的话就为大端。

50101eb9bfae416098850924ece42c0f.png

          如图,我的电脑就是小端存储的


       大家也可以去实验下,自己的电脑是小端存储还是大端存储。 在下一期中我将详细讲解char字符的存储和整形提升相关知识。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C-Sakura

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值