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

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

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,如果不是小端返回值就不会是5elseprintf("大端\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.mzph.cn/news/877512.shtml

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

相关文章

Unity 麦扣 x 勇士传说 全解析 之 怪物基类(2)(附各模块知识的链接,零基础也包学会的牢弟)(案例难度:★★☆☆☆)

1.怪物的动画逻辑一览 2.怪物的受伤死亡逻辑一览 using System.Collections; using System.Collections.Generic; using System.Xml; using UnityEngine;public class Monster : MonoBehaviour {[Header("速度")]public float normalSpeed;public float chaseSpeed;…

在国产芯片上实现YOLOv5/v8图像AI识别-【2.5】yolov8使用C++部署在RK3588更多内容见视频

本专栏主要是提供一种国产化图像识别的解决方案&#xff0c;专栏中实现了YOLOv5/v8在国产化芯片上的使用部署&#xff0c;并可以实现网页端实时查看。根据自己的具体需求可以直接产品化部署使用。 B站配套视频&#xff1a;https://www.bilibili.com/video/BV1or421T74f 背景…

nginx简介及功能

一、简介&#xff1a; 1、nginx、apache是什么&#xff1f; ‌Nginx‌是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。它由伊戈尔赛索耶夫为Rambler.ru站点开发&#xff0c;以其稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而…

OSI七层网络模型 /TCP/IP五层模型以及封装分用的详细讲解

文章目录 协议分层的好处OSI七层网络模型TCP/IP五层网络模型网络设备所在的分层(重点)封装和分用 协议分层的好处 第一点&#xff1a; 在网络通信中&#xff0c;如果使用一个协议来解决所有的问题&#xff0c;那么这个协议就会非常的庞大&#xff0c;非常不利于去学习和理解&…

2023华为od机试C卷【转盘寿司】C 实现 单调栈

#include <stdio.h> #include <stdlib.h>/*单调栈 旋转寿司3 15 6 14 3 21 9 17*/ int main() {int i 0;int len 0;int data 0;int nums[501];char c ;while(scanf("%d",&nums[i]) 1){i;len;c getchar();if(c \n)break;}int *out NULL;int *s…

C语言-部分字符串函数详解 1-4

C语言-部分字符串函数详解 1-4 前言1.strlen1.1基本用法1.2注意事项\0size_t 1.3模拟实现 2.strcpy2.1基本用法2.2注意事项**源字符串必须以 \0 结束****会将源字符串中的 \0拷贝到目标空间****目标空间必须可修改****目标空间必须能容纳下源字符串的内容** 2.3模拟实现 3.strn…

【深度学习】【语音TTS】GPT-SoVITS v2 实战,训练一个人的音色,Docker镜像

文章目录 原理Dockerdocker push训练教程: https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/xyyqrfwiu3e2bgyk 原理 Docker 不用docker不行,不好分配显卡, 做个docker镜像: docker pull pytorch/pytorch:2.1.2

接口基础知识9:详解response body(响应体)

课程大纲 一、定义 HTTP响应体&#xff08;HTTP Response Body&#xff09;&#xff1a;服务器返回给客户端的数据部分&#xff0c;‌它包含了服务器对客户端请求的响应内容&#xff08;如客户端请求的资源、客户端请求的执行结果&#xff09;。 与请求类似&#xff0c;HTTP …

python之matplotlib (3 坐标轴设置)

写在前面 在说明坐标轴设置之前&#xff0c;我有必要和大家说清楚图像设置的一些方法&#xff0c;避免陷入困扰模糊的地步。前面我们说过&#xff0c;画图的三种方法&#xff08;python之matplotlib &#xff08;1 介绍及基本用法&#xff09;-CSDN博客&#xff09;。而设置也…

2024开源资产管理系统推荐 8款免费开源IT资产管理系统/软件

开源资产管理系统 开源资产管理系统是帮助企业管理、跟踪和优化其资产的强大工具。这些系统能够自动记录资产的详细信息&#xff0c;如采购日期、使用情况、维护记录等&#xff0c;从而实现资产的全生命周期管理。企业可以通过这些系统优化资产使用效率&#xff0c;减少资产闲…

【TCP】确认应答、超时重传机制和TCP报头

TCP 相关机制 TCP 基本特点&#xff1a;有连接、可靠传输、面向字节流、全双工 有连接、面向字节流和全双工都能在前面的代码中体现有连接&#xff1a;必须要先调用 accept 建立联系才能处理面向字节流&#xff1a;会拿到 clientSocket 对象的 InputStream 和 OutputStream&a…

python人工智能002:jupyter基本使用

小知识&#xff1a;将jupyter修改为中文&#xff0c;修改用户变量&#xff0c; 注意是用户变量&#xff0c;不是系统变量 新增用户变量 变量名&#xff1a;LANG 变量值&#xff1a;zh_CN.UTF8 然后重启jupyter 上一章的软件安装完成之后&#xff0c;就可以创建文件夹来学习写…

MaxKB(二):Ubuntu24.04搭建maxkb开发环境

接上文&#xff1a;windows10搭建maxkb开发环境&#xff08;劝退指南&#xff09; 上文在windows10环境搭建maxkb开发环境遇到各种坑&#xff0c;后面就转战ubuntu平台&#xff0c;果然比较顺利的完成开发环境搭建。当然遇到相关的问题还是可以参考上文《windows10搭建maxkb开发…

拟合与插值|线性最小二乘拟合|非线性最小二乘拟合|一维插值|二维插值

挖掘数据背后的规律是数学建模的重要任务&#xff0c;拟合与插值是常用的分析方法 掌握拟合与插值的基本概念和方法熟悉Matlab相关程序实现能够从数据中挖掘数学规律 拟合问题的基本提法 拟合问题的概念 已知一组数据(以二维为例)&#xff0c;即平面上n个点 ( x i , y i ) …

C语言指针详解-上

C语言指针详解-上 前言1.指针的基本概念1.1指针是什么1.2指针的声明与初始化1.3取地址符&和解引用符*& 运算符用于**获取变量的地址*** 运算符用于访问指针指向的值 2.指针的类型常见数据类型的指针指针与数组、字符串数组指针结构体指针函数指针二级指针void指针 3.指…

对零基础想转行网络安全同学的一点建议

最近有同学在后台留言&#xff0c;0基础怎么学网络安全&#xff1f;0基础可以转行做网络安全吗&#xff1f;以前也碰到过类似的问题&#xff0c;想了想&#xff0c;今天简单写一下。 我的回答是先了解&#xff0c;再入行。 具体怎么做呢&#xff1f; 首先&#xff0c;你要确…

滑动变阻器的未来发展趋势和前景如何?是否有替代品出现?

滑动变阻器是常见的电子元件&#xff0c;主要用于调节电路中的电阻值。随着科技的不断发展&#xff0c;滑动变阻器的未来发展趋势和前景也引起了广泛关注。 滑动变阻器的未来发展将更加注重智能化&#xff0c;随着物联网、人工智能等技术的快速发展&#xff0c;滑动变阻器也将与…

C语言 | Leetcode C语言题解之第347题前K个高频元素

题目&#xff1a; 题解&#xff1a; struct hash_table {int key;int val;// 查看 https://troydhanson.github.io/uthash/ 了解更多UT_hash_handle hh; };typedef struct hash_table* hash_ptr;struct pair {int first;int second; };void swap(struct pair* a, struct pair*…

YUM和NFS

文章目录 yum软件仓库的提供方式RPM软件包的来源Linux系统各家厂商用的安装源命令---yum 配置本地yum源具体操作 搭建ftp yum仓库环境具体操作实操环境服务端一、安装 vsftpd服务二、创建一个文件&#xff0c;并且挂载三、开启服务四、查看挂载 客户端五、备份六、搭建ftp yum仓…

【联想电脑】:使用拓展坞后转接HDMI,无法识别显示屏

项目场景&#xff1a; 作为一个嵌入式软件开发者&#xff0c;有两个外接屏幕&#xff0c;不足为奇。 但是在今天的使用电脑过程中&#xff0c;出现了接了一个拓展坞上面有HDMI接口&#xff0c;但是HDMI接口接上外接显示屏的时候电脑无法识别到&#xff0c;导致只有电脑直连的HD…