整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

这篇具有很好参考价值的文章主要介绍了整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本篇文章来介绍一下整形在内存中的存储,内容丰富,干货慢慢。

目录

1.整形家族

2.整形在内存中的存储

3.大端小端存储

4.练习

1.整形家族

在开始之前,我们先来简单回顾一下整形家族:

char

        unsigned char

        signed char

short

        unsigned short

        signed short

int 

        unsigned int 

        signed short

long 

        unsigned long

        signed long

long long 

        unsigned long long

        signed long long

看到这里,我想肯定会有小伙伴问为什么 char 也属于整形家族,嘿嘿,那是因为 char 类型在内中存储的其实是字符对应的ASCII值,ASCII值也是整数,所以字符类型也归类到整形家族。

对于 unsigned (无符号)和 signed (有符号):生活中有些数值是有正值和负值,如温度,我们要用有符号类型来存储,我们在使用有符号类型时,signed 是可以省略不写的,例如 int 等同于 singed int ,但是要使用无符号类型时,unsigned 是不可以省略的,例如 unsigned int 。

这里值得注意的是,对于 char 类型来说:只写 char 到底是 unsigned char 还是 signed char C语言是没有明确规定的,只是有些编译器做了规定,如在VS编译器上,char 就等同于 signed char 。

2.整形在内存中的存储

变量的创建是要在内存中开辟空间的,空间的大小是根据不同的类型而决定的。

下来了解下面的概念∶

原码、反码、补码:

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

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

原码:

直接将二进制按照正负数的形式翻译成二进制就可以。符号位是二进制的第一位。

反码:

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

补码:

反码加一就得到补码

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

对于整形来说:数据存放内存中其实存放的是补码。为什么呢?

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

看下面一段代码:

在有符号类型中,二级制表示形式的第一位是符号位,后面位是数值位。

int main()
{
	int num = 10;//创建一个整型变量,叫num,这时num向内存申请4个字节来存放数据
	//整形4个字节 - 32个bit位(二进制位)   正整数原码,反码,补码相同
	//00000000000000000000000000001010 - 原码
	//00000000000000000000000000001010 - 反码
	//00000000000000000000000000001010 - 补码
	//0x 00 00 00 0a  16进制   a是10

	int num2 = -10;
	//10000000000000000000000000001010 - 原码
	//11111111111111111111111111110101 - 反码
	//11111111111111111111111111110110 - 补码
	//0x FF FF FF F6  //16进制
	return 0;
}

我们可以通过调试,来查看内存中的数据,通过&num来得到num的地址,不知道如何调试的可以看我上篇关于如何调试的文章。 0x是表示后面的数是16进制数。

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

本质上内存中存放的是二进制,但VS为了方便显示,显示的是16进制,一个16进制位等于4个二进制位,因为16等于2的4次方。并且还可以发现数据在内存中是倒着存放的,关于为什么后面会讲。

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

 可以发现-10在内存中存放的是一个很大的数,也就是-10的补码。其实对于正整数来说,存放的也是它的补码,只不过是补码,反码,原码相同。

内存中的计算也是通过补码计算的:

上面说到计算机只有加法器,所以当我们计算减法时,是先将被减数换成负数再相加。

下面举一个例子计算1-1,换成加法就是1+(-1)

我们可以先用原码计算一下

00000000000000000000000000000001    1的原码
10000000000000000000000000000001   -1的原码

相加,符号位也相加,得到:
10000000000000000000000000000010    -2

可以发现原码相加的得到是-2,是错误的。下面用补码计算

00000000000000000000000000000001 1的补码

10000000000000000000000000000001   -1的原码  我们把它转换为补码

1111111111111111111111111111111111110   -1的反码  (符号位不变,其他位按位取反)
1111111111111111111111111111111111111   -1的补码  (反码加一)

将1的补码与-1的补码相加得到:
100000000000000000000000000000000  变成33位 要去掉最高位

00000000000000000000000000000000    0  得到0

关于从补码得到原码,有两种方式:

1.通过 原码符号位不变,其他位取反得到反码,反码+1得到补码 这种方式反着推

2.补码 符号位不变,其他位取反,再+1就可得到原码,可以发现与原码得到补码得方式相同,想不到吧,这就是计算机发明者的智慧。

原码,反码,补码之间关系如下图所示: 

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

 这里就可以理解为什么补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路了。

3.大端小端存储

什么是大端小端∶

又称大端小端字节序,是以字节为单位,讨论存储顺序的,8个比特位(二进制位)或两个16进制是一个字节

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

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。为什么有大端和小端∶

为什么会有大小端模式之分呢?

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如一个16bitshort类型x变量,在内存中的地址0x0010x的值为0x1122,那么0x11为数据的高位,0x22为数据的地位。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。大端小端存储是由自己电脑的硬件来决定的。

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

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

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
 

#include<stdio.h>
int main()
{
	int a = 1;
	char b = *(char*)&a;//&a 是int *类型。
	if (b == 1)
	{
		printf("小端字节序存储\n");
	}
	if (b == 0)
	{
		printf("大端字节序存储\n");
	}
	//printf("%d", b);
	return 0;
}

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

 

4.练习

这里一起做做些练习,看看自己掌握的怎么样,顺便再讲一些干货。

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

1. 

#include<stdio.h>

int main()
{
	char a = -1;
	//-1是整数发生截断
	//11111111111111111111111111111111 -1补码
	//11111111 a截断
	signed char b = -1;
	//与a相同
	unsigned char c = -1;
	//11111111111111111111111111111111 -1补码
	//11111111  c截断

	//%d 十进制打印有符号整形数据,发生整型提升
	//整型提升时有符号高位补符号位,无符号补0
	//a 11111111111111111111111111111111补码
	//  11111111111111111111111111111110 反码
	//  10000000000000000000000000000001  -1 原码打印
	//b 和a相同
	//c 111111111  无符号高位补0
	//  00000000000000000000000011111111 255
	printf("a=%d b=%d c=%d", a, b, c);  -1 -1 255
	return 0;
}

2.

#include<stdio.h>

int main()
{
	char a = -128;
	//-128
	//10000000000000000000000000001000000  -128原码
	//11111111111111111111111111110111111   反码
	//11111111111111111111111111111000000   补码
	//10000000//截断
    //打印整形提升
	//11111111111111111111111111111000000
	//补码按%u无符号打印  认为是无符号数,原反补相同,打印一个很大的数
	printf("%u\n", a);
	return 0;
}

3.  与第2道结果相同

#include<stdio.h>

int main()
{
	char a = 128;
    //截断后是与-128截断后相同
    //所以结果也与-128相同
	printf("%u\n", a);
	return 0;
}

4.

#include<stdio.h>
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n", i + j);
	return 0;
}

写到这里是不是有些不敢写-10了,没关系我们来推理一下

10000000000000000000000000010100  -20原码
111111111111111111111111111111101011  -20反码
111111111111111111111111111111101100  -20补码


00000000000000000000000000001010  10补码 与原码相同 与signed int 相同


111111111111111111111111111111110110  i + j  是补码
10000000000000000000000000001001       反码
10000000000000000000000000001010  -10   原码

5.

#include<stdio.h>
#include<Windows.h>
int main()
{
	unsigned int i;//i恒大于0
	for (i = 9; i >= 0; i--)//会死循环 打印很大的数
	{
		printf("%u\n", i);
	}
	return 0;
}

那 i==0 后再 -1 是谁呢。 我们可以看一下 char 类型, -128到127

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

 可以发现开始了循环,同理,当类型位为 unsigned char 时,最大值为255,在加一就是0。

知道了这一点,我们来做一下最后一道题

6.

#include<stdio.h>

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

strlen是求的是 '\0' 之前的字符个数,而'\0'的ASCII码值是0,所以这里计算的是0之前的数组元素个数。

我们可以看 a 数组中的内容 -1,-2,-3 .... -127,-128,因为是char类型的数组,根据上面图片,所以后面是127,126,125 ...2,1,0,-1,... 之后再循环,我们统计 0 之前的元素个数,有128+127=255个,所以答案是255。

本篇结束,下篇讲浮点型数据在内存中的存储文章来源地址https://www.toymoban.com/news/detail-462572.html

到了这里,关于整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言中浮点数居然是这样存储的?(深度剖析)

    大家在写C语言中都用过浮点数float,和double。但是你们知道在内存中是怎么存储的吗? 在生活中我们常见的浮点数: 3.14 1E10 这种科学计数法:由于小数点可以左右移动,所以我们称为浮点数。 C语言常用的浮点数有:            float            doul

    2024年02月11日
    浏览(41)
  • C语言数值表示——进制、数值存储方式

    进制也就是进位制,是人们规定的一种进位方法 对于任何一种进制—X进制,就表示某一位置上的数运算时是逢X进一位 十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x进制就是逢x进位 十进制 二进制 八进制 十六进制 0 0 0 0 1 1 1 1 2 10 2 2 3 11 3

    2024年02月11日
    浏览(35)
  • C语言整数和小数的存储

    计算机使用 二进制进行存储 、运算, 整数 在内存中存储使用的是 二进制补码   整数的2进制表⽰⽅法有三种,即 原码、反码和补码  三种表⽰⽅法均有 符号位 和 数值位 两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最 ⾼位的⼀位是被当做符号位,剩余的

    2024年04月17日
    浏览(21)
  • ML@python@稀疏矩阵的存储和表示@CSR格式

    Sparse matrix - Wikipedia CSR是Compressed Sparse Row的缩写,是一种稀疏矩阵的压缩存储格式。稀疏矩阵是指其中大部分元素为0的矩阵。在机器学习中,由于特征维度通常很高,因此特征矩阵往往是稀疏矩阵。使用CSR格式可以节省存储空间并加快矩阵运算的速度。 在CSR格式中,矩阵被视

    2024年01月22日
    浏览(77)
  • 2023-06-12:如果一个正整数自身是回文数,而且它也是一个回文数的平方,那么我们称这个数为超级回文数。 现在,给定两个正整数 L 和 R (以字符串形式表示), 返回包含在范围 [L, R] 中

    2023-06-12:如果一个正整数自身是回文数,而且它也是一个回文数的平方,那么我们称这个数为超级回文数。 现在,给定两个正整数 L 和 R (以字符串形式表示), 返回包含在范围 [L, R] 中的超级回文数的数目。 输入:L = \\\"4\\\", R = \\\"1000\\\"。 输出:4。 答案2023-06-12: 该算法的基本

    2024年02月08日
    浏览(52)
  • 3.2.3 存储器与CPU的连接(重难点 看完就会)

    本节内容是存储器中的重点和难点,篇幅较长。并不用担忧,看完这片文章,你会对知识点十分了解,并且会用几道题目来巩固一下内容。 由于CPU所要执行的指令和数据都保存在主存当中,并且执行完成后,需要将执行结果保存回主存。二者之间的联系是非常频繁,所以他们

    2024年02月01日
    浏览(51)
  • 【C语言】——动态内存管理与文件操作,后面加一个通讯录福利,万字解读,看完你会有一个全新认识

    目录 一.动态内存管理 1.为什么有动态内存管理 2.malloc和free  2.calloc和realloc 3.柔性数组 二.文件操作 1.为什么使用文件  2.二进制文件和文本文件  3.文件的打开和关闭 4.文件的顺序读写 5.文件缓冲区 三.通讯录  1.预处理  2.基本框架 3.初始化函数 4.增加联系人  5.显示联系人

    2024年03月13日
    浏览(38)
  • C++中如何处理超长的数字(long long类型的整数都无法存储的)

    在 C++中,如果数字超出了 long long 类型的范围,可以考虑使用字符串或第三方库(如 Boost.Multiprecision)来表示和处理超长数字。要使用第三方库需要下载并安装所需的第三方库,在此就不介绍了。 在此介绍使用字符串表示和处理超长数字。本文将介绍使用C++字符串实现超长的

    2024年02月09日
    浏览(41)
  • 04、javascript 修改对象中原有的属性值、修改对象中原有属性的名字(两种方式)、添加对象中新属性等的操作

    其一、代码为: // 想将 obj 中的 flag 值,根据不同的值来变化(即:修改对象中原有的属性值); 其二、页面展示为: 其三、 js 中 for-in 的用法: // for-in 是一种特殊的 for 循环 专门用来循环对象; 注意:普通的 for 循环 可以单独循环、可以循环数组、可以伪数组、但无法循环

    2024年02月09日
    浏览(37)
  • 中原银行 OLAP 架构实时化演进

    中原银行成立于 2014 年,是河南省唯一的省级法人银行,2017 年在香港联交所主板上市,2022 年 5 月经中国银保监会批准正式吸收合并洛阳银行、平顶山银行及焦作中旅银行。合并后总资产突破 1.2 万亿,在国内城市商业银行排名第八位,下辖 18 家分行、700 余家营业网点及

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包