【c语言】整数在内存中的储存(大小端字节序)

news2024/11/18 1:26:34

整数在内存中的储存(大小端字节序)

1.整数在内存中的储存
2.大小端字节序
3.整数在内存中储存例子
4.字节序判断
5.死循环现象

文章目录

  • 整数在内存中的储存(大小端字节序)
  • 整数在内存中的储存
  • 大小端字节序
    • 什么是大小端
    • 为什么会有大小端
  • 整数在内存中储存例子
  • 字节序判断
  • 死循环现象

整数在内存中的储存

在学操作符的时候,我们就知道整数的2进制表示方法有3种,原码,反码,补码
对于有符号整型,这三种表示方法都由符号位和数值位组成,符号位,’0‘表示’正‘,’1‘表示’负‘。
最高位为符号位,其余的为数值位。

对于有符号整型

正整数原码,反码,补码相同
负整数:
原码:直接将数值按照正负形式翻译成二进制
反码:原码符号位不变,数值位取反
补码:反码加1

对于无符号数据

原码反码补码相同

对于整形数据来说:内存中存放的是数据的补码

因为补码可以对符号位和数值域统一处理,同样,加法减法也可以统一处理,补码与原码互相转换,他的运算过程是相同的,不需要额外的硬件电路

大小端字节序

在学习大小端字节序之前我们先来梳理几个小知识

1.一个字节——>8个二进制位
一个16进制位——>4个二进制位
两个16进制位——>8个二进制位
2.在计算机系统中,内存被分为一个个字节单元,字节单元的编号==地址

下面给一个代码,试着调试看一看

int main()
{
	int a = 0x11223344;//这里给出一个整型a,用16进制给初始化一下
	
	return 0;
}

调试看结果
在这里插入图片描述
我们不难看出a中的0X11223344这个数字是按照字节为单位,倒着存放的,这是为什么呢?

这就不得不提到大小端了。

什么是大小端

当我们在内存储存超过一个字节的数据时,就存在储存顺序的问题,我们分为大端字节序储存和小端字节序储存

大端储存:

是指数据的低字节内容保存在高地址处,而数据得高字节内容保存在低地址处。

小端储存:

是指数据得低字节内容保存在低地址处,而数据的高地址内容保存在高地址处。

上边使用的VS2022,他是小端储存模式,所以按照小端的储存模式规则,他在内存中字节序是倒着储存的。

为什么会有大小端

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

比如,对于一个16个bit位的X,他在内存中的地址为0x0010,X的值是0x1122,那么0X11是高字节位,0X22是低字节位,在大端模式中,0x11应该放在低地址处,即0X0010,0X22应该放在高地址处,即0X0011中。小端模式,则恰好相反。

我们常用的X86结构是小端模式,而KEIL C51为大端模式。很多的ARM,DSP都是小端模式。有些ARM处理器还可以由硬件来选择大小端

整数在内存中储存例子

1.写一个程序来判断当前机器的字节序
分析一波
我们可以先创建一个整型变量,int a=1
这个数据在小端模式下储存的应该是

01 00 00 00

大端模式下储存的应该是

00 00 00 01,

因此想要判断当前机器是那种字节序,只需要拿出第一个字节比一比就行

如何把它取出来呢?

我们知道当我们对一个数据取地址时,得到的地址是较小的字节单元的地址,(这一点可以看一下博主的指针知识点总结,有讲到这里)而内存的储存是从低地址向高地址储存的,因此我们可以对a取地址就可以锁定到第一个字节,再将它强制类型转换成字符指针类型,然后解引用就可以得到第一个字节了

*(char *)&a;

由此,写出代码

int Check_c(int i)
{
    return *(char*)&i;
}
int main()
{
	int i = 5;
	int ret=Check_c(i);
	if (ret == 5)
		printf("小端\n");//如果当前的系统储存方式是小端,就能输出5,如果不是小端返回值就不会是5
	else
		printf("大端\n");
	return 0;
}

下面再通过几道题,再理解一下

2.

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

再分析之前,先来复习一下整型提升的知识

对于有符号整数提升是按照变量的数据类型的符号位来提升
对于无符号整数提升,高位补0

分析一波
我们先写出-1的原码反码补码

-1
原码:10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110
补码:11111111 111111111 11111111 1111111

又因为a,b,c均是char类型,这里截断一下,a,b,c都是
11111111

在输出的时候要以有符号整形输出,那么就要发生整型提升

对于a,他是有符号的char类型,高位补1,得到完整的补码,

11111111 11111111 11111111 11111111

对其补码取反加1,得到的原码为

10000000 00000000 00000000 00000001

输出仍为-1,而对于b,他也是有符号char类型,与a一样,输出-1

对于c,他是无符号类型,做完整型提升得到补码

00000000 00000000 00000000 11111111

同时这也是c的原码,输出255

看一下运行结果
在这里插入图片描述
3.

int main()
{
	char a = 128;
	char b = -128;
	printf("a=%u b=%u", a, b);
	return 0;
}

在分析之前,还是先来复习一下知识

char类型通常是一个8位的有符号整数,取值范围在-128~127
unsigned char 类型是8位的无符号整数,取值范围在0~255

这里我们分析a,b,他们的原反补码如下

-128
原码:10000000 00000000 00000000 10000000
反码:11111111 11111111 11111111 01111111
补码:11111111 11111111 11111111 10000000

a,b是char 类型,截断得到a,b是
10000000
对a,b整型提升后补码

11111111 11111111 11111111 10000000

因为输出的是无符号整型,a,b的原码反码补码一样,输出的是一个很大的数
看运行结果
在这里插入图片描述

在这里尽管a=128,已经超出char类型的取值范围,但并不影响,因为在char类型里边他总会把赋给它的值通过各种截断,让他在他的取值范围内
而我们看到在截断后,a,b的值是一样的,所以他整型提升后,结果也是一样的

4.

int main()
{
	unsigned char a = 200;
	unsigned char b = 100;
	unsigned char c = 0;
	c = a + b;
	printf(" % d % d", a + b, c);
	return 0;
}

先分别求出a,b的反码

a的反码:00000000 00000000 00000000 11001000
b的反码:00000000 00000000 00000000 01100100

那么在unsigned char的类型中

a:11001000
b:01100100
a+b:1 00101100
对他做整型提升高位补0
00000000 00000000 00000001 00101100(原码,反码,补码)——>对应的就是十进制的300

而c=a+b;,
虽然unsigned char 下的a+b仍为1 00101100,但c是char类型,要丢掉高位的1,c为 00101100,对其进行整型提升,高位补0,

00000000 00000000 00000000 00101100,对应十进制的44

在这里插入图片描述

字节序判断

1.

unsigned int a= 0x1234;
unsigned char b = *(unsigned char *)&a;

在32位大端模式处理器上变量b等于?
分析

对于a,a=0x00001234,前边的0被省略掉了,那么在大端模式下,他在内存中字节的储存顺序为

00 00 12 34

*(unsigned char *)&a;这个操作就是把低地址的字节00拿出来(在上边写个代码判断当前机器是大端小端的时候就已经介绍过了)

*(unsigned char *)&a;被赋值给b,b的值就是0x00

当以“%x"形式输出16进制时,0x,和前边的0都会被省略
如果想要输出0x,就以"%#x"形式输出
2.

//X86环境,小端字节序
int main()
{
	int arr[4] = { 1,2,3,4 };
	int* ptr1 = (int*)(&arr + 1);
	int* ptr2 = (int*)((int)arr + 1);
	printf("%x, %x", ptr1[-1], *ptr2);
	return 0;
}

在小端模式下,数组元素在内存中字节的储存顺序是
在这里插入图片描述
对ptr1

&arr+1,对整个数组取地址加1,跳过整个数组
ptr1[-1]=*(ptr1-1)

指向如图所示,04 00 00 00,那么对应的数据就是0x 00000004,0x,和前边的0省略掉,输出4

对于ptr2

arr指向的是arr首元素地址。假设arr=0x0000EF10,将他强制转换成整数类型,整数类型加1就是单纯加个1,(int)arr+1=)0x0000EF11,跳过一个地址(字节)跳到下一个字节,这时对ptr2解引用指向的是

00 00 00 02
对应的数据是0x 02 00 00 00,输出2000000

在这里插入图片描述

死循环现象

这里我们在学习一个知识
在这里插入图片描述
我们通过这个图片可以明白,在char类型中,他的取值范围是形成一个圆环一直在循环的,(其他类型也是如此)也就是说,比如我们给char a=500,很显然,他超出了char的取值范围,可是根据这个规律,当他截断后放在char类型里边的数就是500%256=244,对应的就是-12。
再例如unsigneg char b=400,也超出了unsigned char 的范围,根据这个规律,当他截断后放在unsigned char类型里的数是400%256=144,对应的就是144
在这里插入图片描述
运行的结果也是如此

学习过这个之后,就可以看几道题了
1.


#include<stdio.h>
#include<string.h>
int main()
{
	char arr[1000];
	int u = 0;
	for (u = 0; u < 1000; u++)
	{
		arr[u] = -1 - u;
	}
	printf("%d", strlen(arr));
	return 0;
}

分析一波
strlen计算数组元素的个数,并且必需要碰到‘\0’才能结束,
在上边代码中,初始化arr数组,如果不考虑arr的类型,他的初始化值是从-1到-999,可是他受到char类型的限制,char类型的取值范围在-128~127,这时候就要发生截断,总之char类型会想办法让初始化的值在他的取值范围内。那么arr的初始化值就会是

-1,-2,-3,…-127,-128,-129这时候-129已经超出char的范围,char想办法让他满足自己的范围,那么根据上边学习的规律-129放在char类型里就是127,

在接下来就是127,126,125…2,1,0,-128,-127.就这样循环下去
因为’\0’对应的ASCII码是0,所以strlen会计算’\0’之前的字符个数为128+127=255
在这里插入图片描述
2.

int main()
{
	unsigned int i = 0;
	for (i = 0; i <= 255; i++)
	{
		printf("haha\n");
	}
	return 0;
}
int main()
{
	unsigned int j = 0;
	for (j = 12; j >= 0; j--)
	{
		printf("hehe\n");
	}
	return 0;
}

这两段代码,无一例外他们的结果最后都是死循环。
分析
对第一个

unsigned int类型的取值范围0到255,在第一个循环中,i加到266时,超出unsigned int的范围,unsigned int将他转化成符合自己范围的数值即根据规律计算出是0,这样循环条件恒成立,就陷入了死循环

同理第二段代码

当j 减到0时,再减变为-1,不满足unsigned int的取值范围,unsigned int将他转化成符合自己范围的值,根据上边学习的内容计算出时255,循环条件恒成立,陷入死循环

作者有话说:作者只是一只小白,以上解释均是作者对已学知识的理解,巩固,复习。希望可以帮到大家,如有错误,感谢指出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2066301.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TinaLinux NPU开发

MobileNet V2 MobileNet V2是一种轻量级的卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;专门设计用于在移动设备和嵌入式设备上进行计算资源受限的实时图像分类和目标检测任务。 以下是MobileNet V2的一些关键特点和创新之处&#xff1a; Depthwise Separable Co…

鸿蒙OS promptAction的使用

效果如下&#xff1a; import { promptAction } from kit.ArkUIlet customDialogId: number 0Builder function customDialogBuilder() {Column() {Blank().height(30)Text(确定要删除吗&#xff1f;).fontSize(15)Blank().height(40)Row() {Button("取消").onClick…

【中仕公考怎么样】2024下半年事业编联考冲刺!

多地下半年事业单位联考公告发布!11月2日笔试! 笔试时间&#xff1a;2024年11月2日(周六)上午。 08:30—10:00 《职业能力倾向测验》10:00—12:00 《综合应用能力》 考试科目&#xff1a; 综合应用能力(A类) 社会科学专技类(B类) 自然科学专技类(C类) 中小学教师类(D类) 医…

.[RestoreBackup@cock.li].SRC勒索病毒数据怎么处理|数据解密恢复

导言&#xff1a; 在数字化时代&#xff0c;信息技术的飞速发展极大地促进了社会进步与经济繁荣&#xff0c;但同时也为网络犯罪分子提供了前所未有的便利。近年来&#xff0c;勒索病毒作为一种新兴的网络威胁&#xff0c;正以前所未有的速度和规模肆虐全球&#xff0c;给个人…

鸿蒙实现在图片上进行标注

一.实现思路 现在需求是&#xff1a;后端会返回在这张图片上的相对位置&#xff0c;然后前端这边需要在图片上进行标注&#xff0c;就是画个框框圈起来&#xff0c;返回的数据里包括当前框的x,y坐标和图片大小&#xff0c;大体思路就是使用canvas绘制&#xff0c;使用鸿蒙的st…

游戏app激励视频广告预加载位置,最大化广告收益

最近收到很多游戏类App开发者咨询激励视频广告&#xff0c;在帮助开发者分析产品的时候&#xff0c;特别是一些初级开发者的App产品&#xff0c;发现用户进入这些App&#xff0c;或者打开某个功能时就弹出激励视频广告&#xff0c;这样是违规的&#xff0c;并且用户看完广告也是…

golang每日一库——casbin开源的访问控制框架

文章目录 casbincasbin工作原理——PERM请求——Request策略——Policy匹配器——Matcher效果——Effect Model语法Request定义Policy定义Policy effect定义Matchers定义 编辑器例子1例子2例子3例子4例子5例子6例子7例子8例子9 casbin Casbin是一个强大且高效的开源访问控制库…

软件测试基础:功能测试知识详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、测试项目启动与研读需求文档 &#xff08;一&#xff09; 组建测试团队 1、测试团队中的角色 2、测试团队的基本责任 尽早地发现软件程序、系统或产品中…

postman使用指北

粘贴 cURL 请求 环境设置 作用&#xff1a;方便切换不同环境&#xff0c;比如配置本地环境/测试环境/线上环境&#xff0c;通过切换环境就可以请求对应环境的接口 配置环境 切换环境请求 Pre-request Script 可以在发送请求之前执行一些脚本操作 1. 常用指令 // 获取请求方…

C++中const的用法

const 我们都见过&#xff0c;但是今天&#xff0c;我们会从头开始重新再说const的所有用法。 一、const修饰普通变量 当我们定义一个变量时&#xff0c;前面加上const修饰的话&#xff0c;这个变量将不再能被修改&#xff0c;称之为常变量。例如&#xff1a; int a10; a20;…

ESD分类和等级划分

1、HBM&#xff1a;Human Body Model&#xff0c;人体模型 2、CDM&#xff1a;Charged Device Model&#xff0c;充电器件模型 3、MM&#xff1a;Machine Model&#xff0c;机器模型&#xff1a; 数据来源网站

总结Java文件操作

文件&#xff1a;文件是一个广义的概念 在操作系统中文件可以指硬件资源和软件资源为文件&#xff1b;也可以指存储在硬盘上的文件&#xff0c;文件夹也是文件&#xff1b;文件夹是通俗的叫法&#xff0c;专业的叫法是目录&#xff1b; 查看我们的硬盘&#xff0c;我们可以发…

C语言分析数据在内存中的存储一:(整形在内存中的存储)

数据类型介绍 我们知道C语言有很多内置类型&#xff1a; char //字符数据类型 1 个字节short //短整型 2 个字节int //整形 4 个字节long //长整形 4 个字节long long //更长的整形 8 个字节float //单精度浮点数 4 个字节dou…

Linux学习记录(十三)----信号

文章目录 6.信号1.信号的发送&#xff08;发送信号进程&#xff09;kill:raise:alarm : 2.信号的接收3.信号的处理信号父子进程间通信 7.信号灯(semaphore)创建信号灯函数控制信号灯函数PV操作 声明&#xff1a;本人撰写的为学习笔记内容来源于网络&#xff0c;如有侵权联系删除…

SQL Server中如何自动抓取阻塞

背景 当发数据库生阻塞时&#xff0c;可以通过SQL语句来获取当前阻塞的会话情况&#xff0c;可以得到下面的信息 说明&#xff1a;会话55阻塞了会话53。两个会话都执行了update test set fid10 where fid0。 但我们也经常碰到客户生产环境出现阻塞&#xff0c;由于不会抓取或者…

YOLOv8实现任意目录下命令行训练

问题 当你使用YOLOv8命令行训练模型的时候&#xff0c;如果当前执行的目录下没有相关的预训练模型文件&#xff0c;YOLOv8就会自动下载模型权重文件。这个是一个正常操作&#xff0c;但是你还会发现&#xff0c;当你在参数model中指定已有的&#xff0c;在其他目录下的预训练模…

实际案例:某日化集团主数据建设项目

一、建设背景1. 背景分析当前&#xff0c;该日化企业集团的主数据尚处于分散状态&#xff0c;分布于各业务系统中&#xff0c;缺乏一套专业的主数据管理系统进行统一管理。因此&#xff0c;数据无法在全集团范围内共享使用&#xff0c;且在业务端到端的流程拉通时&#xff0c;数…

WPS关闭后,进程依然在后台运行的解决办法

问题 wps启动后 在启动wps后&#xff0c;什么都不做&#xff0c;打开进程管理器&#xff0c;发现居然运行了3个wps进程&#xff1a; win10只会显示wps进程&#xff1a; win11显示比较准确&#xff1a; 关闭后 在关闭wps&#xff0c;再去任务管理器查看&#xff0c;发现在…

游戏开发设计模式之策略模式

目录 策略模式在游戏开发中的具体应用案例有哪些&#xff1f; 如何在Unity中实现策略模式以优化角色行为和AI策略&#xff1f; 策略模式与其他设计模式&#xff08;如观察者模式、状态模式&#xff09;在游戏开发中的比较优势是什么&#xff1f; 策略模式的优势 观察者模式…

基于SpringBoot的闲一品交易平台

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 Java技术 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 管理员…