博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
整型数据的存储和相关练习题
阅读量:3952 次
发布时间:2019-05-24

本文共 4452 字,大约阅读时间需要 14 分钟。

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

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

原码 直接将二进制按照正负数的形式翻译成二进制就可以。

反码 将原码的符号位不变,其他位依次按位取反就可以得到了。

补码 反码+1就得到补码。

正数的原、反、补码都相同。

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同 时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需 要额外的硬件电路。

 

存储分两种模式:大端&&小端

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

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

 

举个例子:int a = 20;

a 的原码是 :00000000 00000000 00000000 00010100 . 因为 a 是一个有正数,所以,补码也就是原码。即 a 在内存中的存储就是以 00000000 00000000 00000000 00010100 存储的。

在内存中是 14 00 00 00 ,这14本身是低位并且存在了内存对应的物理低位,所以这就是一个小端存储。

 

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一 个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具 体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字 节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。 例如一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小 端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小 端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

下面看一段代码

#include 
int main(){ char a = -1; signed char b = -1; unsigned char c = -1; printf("a=%d,b=%d,c=%d", a, b, c); system("pause"); return 0;}

结果 a 和 b 都是 -1,那为什么 c 成了 255?

回到一开始,我们说整型数据在内存中存的是补码。

因为 a 和 b 都是有符号的

原码:  10000000 00000000 00000000 00000001

反码:  11111111 11111111 11111111 11111110

补码:  11111111 11111111 11111111 11111111

-1本来是一个整型的数,所以有 4 个字节,但是将 -1 给了char 类型的变量 a 和 b ,所以,存的时候需要 “截断”,就是将 4 个字节中最后一个字节的数给 char 类型的变量 a ,b 。即截断了 “11111111” 在最后输出的时候,输出类型是 %d,是整型,但是前边才说了,整型四个字节,字符型一个字节,存字符型的时候已经进行了一个截断,那输出整型的时候就要有一个 “提升”。“提升” 说的是,如果一个数本身是有符号的,那就在截断之后这个数前边在补上三个字节的符号位的数,如果是无符号的,就补上三个字节的 0.比如我们这里的变量 a,和 b,都是有符号的,截断后是 11111111 ,符号位也就是最高位是1,所以我们在前边补上三个字节的 1.

所以转为 int 型就是: 11111111 11111111 11111111 11111111

输出的时候,先给这个数减 1 ,转为这个数的反码,然后再取反,转为原码:便是 -1.所以 a b输出结果为 -1.

但是 c 是无符号的

原码:  00000000 00000000 00000000 00000001

反码:  01111111 11111111 11111111 11111110
补码:  01111111 11111111 11111111 11111111
截断 截取 11111111

因为是无符号的所以提升后的结果是 00000000 00000000 00000000 11111111

注意这里又有一个圈子,我们要输出它的时候,还要再给他减 1,再取反求原码吗? 不,不用了,因为这个数是正数了,原码反码补码都是这个数。可能有这么一个疑问,就是说,一开始赋值不是给的是 -1吗,为啥这里变成了正数,因为 -1 给进去,我们截断了,只取了最后一个字节,当输出 %d 也就是整型输出的时候,还有这个提升过程,因为是无符号的,所以提升往前边补了三个字节的 0 ,最后提升完这个数  00000000 00000000 00000000 11111111,这才是要输出的数,这个数的符号位现在是 0,也就是说它已经是一个正数了,这个码,已经是一个原码了,所以输出便是 255.

 

第二题

#include 
int main(){ char a = -128; printf("%u\n",a); return 0;}

这个结果是怎么来的?

回到整型的存储方式,存的是补码

原码 : 10000000 00000000 00000000 10000000

反码 : 11111111 11111111 11111111 011111111

补码 : 11111111 11111111 11111111 10000000

存储的时候还是先截断,截断了 10000000,然后提升,因为这是一个 char 类型的,并且是一个负数,所以补三个字节的符号位——1. 提升完之后结果就是11111111 11111111 11111111 10000000 ,因为输出的时候无符号整型,所以就是输出提升完的结果。即4,294,967,168‬。

接着把题稍作改动

#include 
int main(){ char a = 128; printf("%u\n", a); system("pause"); return 0;}

将原来的 char = -128 改成 char = 128.结果如何呢?

 

还是一样的结果,稍做分析。

原码: 00000000 00000000 00000000 10000000 

反码: 01111111 11111111 11111111 01111111

补码: 01111111 11111111 11111111 10000000

截断截取的是 10000000,然后提升,因为是 char型的,所以有符号,看符号位,现在的符号位是 1,所以在前边再补三个字节的 1 ,结果便是 11111111 11111111 11111111 10000000,与上边的 char a = -128是一样的结果,所以最终打印出来也是4,294,967,168‬。

 

下一题

#include 
int main(){ int i = -20; unsigned int j = 10; printf("%d\n", i + j); system("pause"); return 0;}

i的原码: 10000000 0000000 0000000 00010100

i的反码: 11111111 11111111 11111111 11101011

i的补码: 11111111 11111111 11111111 11101100

j的补码: 00000000 00000000 00000000 00001010

将 i 和 j 的补码进行相加 结果是  11111111 11111111 11111111 11110110

最高位是符号位是一个负数,所以输出的时候,先减一再取反,结果是 10000000 00000000 00000000 00001010,打印出来便是 -1.

 

手动分割线

------------------------------------------------------------------------------------------------

#include 
int main(){ unsigned int i; for (i = 9; i >= 0; i--) { printf("%u\n", i ); } system("pause"); return 0;}

这个结果不多说,陷入死循环,因为是无符号的,所以不可能小于0.

下一题

int main(){    char a[1000];    int i;    for(i=0; i<1000; i++)   {        a[i] = -1-i;   }    printf("%d",strlen(a));    return 0;}

结果是 255

当 i = 255的时候,-1-255 = -256.

- 256的原码 :10000000 00000000 00000001 00000000

            反码: 11111111 11111111 11111110 11111111

            补码: 11111111 11111111 11111111 00000000

截断存进去的是 00000000,存的是 0 ,而 '\0' 的ASCII 值刚好是 0.所以只存到 i = 254,而数组从 0 开始,所以长度是255.

 

下一题

#include 
unsigned char i = 0;int main(){ for(i = 0;i<=255;i++) { printf("hello world\n"); } return 0;}

简单一说,这道题也是一个死循环,因为 i 是一个无符号的,当加到 255(11111111),再加 1,就会变成 00000000 同时进一位,但是 char 所截取的 是 00000000,所以会一直小于 255,陷入死循环。

转载地址:http://oqwzi.baihongyu.com/

你可能感兴趣的文章
先搞懂这八大基础概念,再谈机器学习入门!
查看>>
2017年深度学习必读31篇论文(附下载地址)
查看>>
数据看穿一生:前半生赚钱养娃,后半生赚钱买命
查看>>
【资源】年底送你一套编程视频(含源码)
查看>>
用Python给“冲顶大会”做外挂!王思聪们还敢撒币吗?
查看>>
用算法撩妹都不会,别跟我说你是程序员(文末附Python零基础入门课程)
查看>>
2017人工智能与机器学习年终盘点(重要工具资源汇总)
查看>>
收藏!超全机器学习资料合集!(附下载)
查看>>
绝地求生外挂源代码被公布,或迎神仙大战时代?
查看>>
火爆全球的区块链到底是怎么一回事?一文带你看懂
查看>>
当白帽黑客遇到了网络诈骗,他是如何套路并反制骗子的?
查看>>
手把手教你36小时搭建无人超市系统 !(附代码)
查看>>
2017新生儿爆款名字出炉!90后的父母们最受欢迎的居然是.....
查看>>
全景图解高铁数据,谁是最有潜力的高铁城市?
查看>>
张小龙现场“约战”跳一跳,发布2018微信全新计划(内附演讲全文)
查看>>
爬取电影天堂的最新电影
查看>>
运维总监不会告诉你这些有趣但鲜为人知的 Linux 命令
查看>>
2017新浪微整形年度大数据报告
查看>>
实战 | 用 Python 选股票,据说可以多挣个20%
查看>>
重磅 | 数据挖掘之父韩家炜:文本语料库的数据挖掘(附视频+PPT下载)
查看>>