C语言之数据在内存中的存储(1),整形与大小端字节序

news2024/9/20 20:29:30


目录

前言

一、整形数据在内存中的存储

二、大小端字节序

三、大小端字节序的判断

四、字符型数据在内存中的存储

总结



前言

     本文主要讲述整型包括字符型是如何在内存中存储的,涉及到大小端字节序这一概念,还有如何判断大小端,希望对大家有所帮助


❤️感谢支持,点赞关注不迷路❤️


(本文内容涉及到整形提升,如不了解,主页中可查看详细,两篇结合起来看更深入)

一、整形数据在内存中的存储

我们都知道。整数的2进制表示有3种,即原码、反码、补码

     

有符号的整数,三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表 示“负”,最高位的一位是被当做符号位,剩余的都是数值位。

  • 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。
  • 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
  • 补码:反码+1就得到补码。

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

负整数的三种表示方法各不相同。

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

为什么呢?

     

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

(主页·位操作符有详细举例)


二、大小端字节序

运行以下代码,在vs(32位)调试窗口观察其在内存中的存储情况

#include <stdio.h>

int main()
{
	int a = 0x11223344;

	return 0;
}

内存调试窗口:

(0x0058FB3C是a在内存中的首地址)

发现:a = 0x11223344,它在内存中存储的却是 44 33 22 11,是倒着存储的。相信我们平时调试的时候肯定会有这样的疑问,这就涉及到了大小端字节序了。

什么是大小端?

其实超过一个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为大端字节序存储和小端字节序存储,下面是具体的概念:

  • 大端(存储)模式: 是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处。
  • 小端(存储)模式: 是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。

解释说明:例如上面的 a = 0x11223344,我们按照数学方式读这个数时,44是不是个位和十位。它相比于前面的 112233 是不是算低位。44 就是一个低位字节内容,VS是以小端模式存储数据的,所以 44 就存储在内存的低地址处,其余的就按顺序往高处存储,这样我们看到的就是 44 33 22 11了。那么假如我们用的是大端模式存储数据的,那么我们看到的就是 11 22 33 44 ,11在内存中对应的是低地址,44 是高地址。

为什么有大小端?

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

    

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8 bit 位,但是在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处理器还可以由硬件来选择是大端模式还是小端模式。


三、大小端字节序的判断

判断大小端其实很简单,定义 int a = 1,16进制为 0x 00 00 00 01,我们只需要访问其首地址对应的字节内容即可,小端会以 0x 01 00 00 00 从低地址往高地址排放,大端会以 0x 00 00 00 01 从低地址往高地址排放。

如下,一小段代码即可:

#include <stdio.h>

int check_sys()
{
	int a = 1;

	return *(char*)(&a);
}

int main()
{
	int ret = check_sys();

	if (ret == 1)
	{
		printf("小端\n");
	}
	else if (ret == 0)
	{
		printf("大端\n");
	}

	return 0;
}

运行结果(VS):


四、字符型数据在内存中的存储

字符型其实也属于整形范畴,存储的是其ASCII码值。

我们可以先观察以下代码:

#include <stdio.h>

int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;

	printf("a=%d, b=%d, c=%d\n", a, b, c);

	return 0;
}

运行结果:

解疑:

  1. 首先我们知道,字符型变量以%d打印时是要发生整形提升的。
  2. 然后a为char类型,vs中,char类型默认为有符号字符型,也就是等同于 signed char,所以a整形提升是要看符号位的,-1的补码是11111111 11111111 11111111 11111111,a大小只有一个字节,存储时会发生截断取后8位,a其补码为11111111,整形提升后 11111111 11111111 11111111 11111111,以%d打印的是原码,再转为原码为10000000 00000000 00000000 00000001,因此打印的还是-1
  3. b与a一样,然后就是c,c是无符号字符形,c的补码还是1111111,整形提升,无符号整形提升高位补0,也就是 00000000 00000000 00000000 11111111,再转为原码,因为是无符号整形,原反补相同,所以原码还是 00000000 00000000 00000000 11111111,打印出来就是255。


在看这段代码:

#include <stdio.h>

int main()
{
	char a = -128;

	printf("%u\n", a);
	printf("%d\n", a);

	return 0;
}

运行结果:

解疑:

  1. 我们发现以%u(无符号整形)方式打印时,打印出的是一个非常大的数字,以%d打印还是原数值,那么为什么会这样呢
  2. 首先,a以%u打印时,还是会发生整形提升,-128有点大,我们先算出-128的原码为  10000000 00000000 00000000 10000000,取反加1算出-128的补码为 11111111 11111111 11111111 10000000,截断后 a 的补码就是10000000,以%u打印,虽然是以无符号整形打印,但是整形提升时是根据原类型进行提升的,原类型为char,有符号字符型,所以高位补符号位1,即 11111111 11111111 11111111 10000000。然后%u就发挥作用了,要把整形提升后的这个补码看成无符号整形,这时候原反补就相同,原码就是 1111111 11111111 11111111 10000000,打印出来的结果就是上图中很大的数字,我们可以借助计算器验证:
  3. 以%d打印时接着2中整形提升后的补码 11111111 11111111 11111111 10000000,这里是以%d打印,所以要看成有符号的整形,其原码就要进行取反加1,即 10000000 00000000 00000000 10000000,打印出来就是-128


再看这段代码:

#include <stdio.h>

int main()
{
	char a = 128;

	printf("%u\n", a);
	printf("%d\n", a);

	return 0;
}

运行结果:

解疑:

  1. 我们发现128的结果与-128的结果相同,这又是为什么
  2. 其实我们自己再重新算一下就会发现,a存储时补码都是 10000000,因为128与-128的补码后8位是完全相同的,截断时值就相同。算一个特殊情况,因为a的值相同,所以后续以%u或者%d打印时效果也相同。


通过以上例题,我们可以再推导一下char型变量(有符号)的存储范围为啥是 -128~127了,还有 unsigned char 为啥是 0~255

我们画图分析:

如此,我们可以画成一个圆:

这就是 char 类型为什么存储范围是-128~127,哪怕赋值的数字超过这个范围,也会被截断在这个范围内。

这就是unsigned char 存储范围为什么是0~255。

其实,signed short 和 unsigned short 类型数据也可以画圆圈表示,int也可以,这里如果感兴趣可以自己画着试试。同上即可


 

总结

        以上就是本文的全部内容,希望对你有所帮助。

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

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

相关文章

大语言模型的直接偏好优化(DPO)对齐在PAI-QuickStart实践

直接偏好优化&#xff08;Direct Preference Optimization&#xff0c;DPO)算法是大语言模型对齐的经典算法之一&#xff0c;它巧妙地将奖励模型&#xff08;Reward Model&#xff09;训练和强化学习&#xff08;RL&#xff09;两个步骤合并成了一个&#xff0c;使得训练更加快…

Python 基础知识:为什么使用 __init__.py ?

大家好&#xff01;今天&#xff0c;我们将深入了解 Python 中的 __init__.py 文件&#xff0c;这个小文件却能干大事。让我们抛开任何专业术语&#xff0c;直接进入正题。 什么是 __init__.py &#xff1f; 假设你有一个 Python 目录&#xff0c;里面有一堆 Python 文件&…

vue3【实战】语义化首页布局

技术要点&#xff0c;详见注释 <script setup></script><template><div class"page"><header>页头</header><nav>导航</nav><!-- 主体内容 --><main class"row"><aside>左侧边栏<s…

JavaDS —— 顺序表ArrayList

顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存储。在数组上完成数据的增删查改。在物理和逻辑上都是连续的。 模拟实现 下面是我们要自己模拟实现的方法&#xff1a; 首先我们要创建一个顺序表&#xff0c;顺序表…

C++初探究

概述 C可以追溯到1979年&#xff0c;C之父Bjarne Stroustrup在在使用C语言研发工作时发现C语言的不足&#xff0c;并想要将其改进&#xff0c;到1983年&#xff0c;Bjarne Stroustrup在C语言的基础上添加了面向对象编程的特性&#xff0c;设计出了C的雏形。 网址推荐 C官方文…

C++继承(一文说懂)

目录 一&#xff1a; &#x1f525;继承的概念及定义1.1 继承的概念1.2 继承定义1.2.1 定义格式1.2.2 继承关系和访问限定符1.2.3 继承基类成员访问方式的变化 二&#xff1a;&#x1f525;基类和派生类对象赋值转换三&#xff1a;&#x1f525;继承中的作用域四&#xff1a;&a…

太多项会毁了回归

「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础 人工智能Python基础 人工智能基础核心知识 人工智能BI核心知识 人工智能CV核心知识 多项式回归的过度拟合及其避免方法 通过添加现有特征的幂&#xff0c;多项式回归可以帮助你充分利用数据集。它允许我们甚至使用简…

Java学习高级二

Java是单继承的 Object类 方法重写 Java子类访问 – 就近原则 子类构造器的特点 多态 Java–final

【豆包AI】北京春田知韵

看到有国内AI上线了&#xff0c;网络信息那么多&#xff0c;我该怎么找它的官网呢&#xff1f; 找官方网站3步 1百度 关于抖音豆包的网站是哪个?【www.doubao.com】 豆包属于哪个公司&#xff1f;【北京春田知韵科技有限公司】 www.doubao.com 2查询备案号 PC版本的安装…

理解算法复杂度:时间复杂度详解

引言 在计算机科学中&#xff0c;算法复杂度是衡量算法效率的重要指标。时间复杂度和空间复杂度是算法复杂度的两个主要方面。在这篇博客中&#xff0c;我们将深入探讨时间复杂度&#xff0c;了解其定义、常见类型以及如何进行分析。 什么是时间复杂度&#xff1f; 时间复杂度…

论文《Generalizable Adversarial Attacks Using Generative Models》笔记

【DAGAER】传统的攻击方法依赖于约束优化范式&#xff0c;具有局限性&#xff0c;例如经典的Nettack攻击方法。本文提出了一个统一的白盒对抗攻击生成框架&#xff0c;该方法学习了目标域的深度生成模型&#xff0c;不是在原始输入空间中生成对抗性例子&#xff0c;而是学习在一…

elk在宝塔中的简单部署和使用

ELK是什么&#xff1f;了解elk “ELK” 是 Elasticsearch、Logstash 和 Kibana 三个开源软件的首字母缩写。这三个软件一起常被称为 “ELK Stack” 或 “Elastic Stack”。它们主要用于日志管理和分析&#xff0c;提供了强大的数据搜索、分析和可视化功能。 Elasticsearch&am…

C++初阶学习第一弹——入门学习C++

目录 1.什么是C 2.C关键字 3.命名空间 3.1命名空间的定义 3.2命名空间的使用 1、加命名空间名称及作用域限定符 2、使用 using 将命名空间中某个成员引入 3.使用using namespace 命名空间名称 引入 4.C输入&输出 5.缺省参数 5.1 缺省参数概念 5.2缺省参数分类 6. …

Dungeonborne卡顿延迟怎么办?这样降低Dungeonborne延迟

Dungeonborne将第一人称的动作的即时性和经典的西幻RPG职业设计深度结合&#xff0c;带来无与伦比的游戏体验。玩家在游戏中扮演一位从神秘地牢中醒来的勇士&#xff0c;他必须面对各种未知的敌人和挑战&#xff0c;逐渐揭开自己的身世之谜。在这个充满魔法和奇迹的世界里&…

【计算机毕业设计】015基于weixin小程序校园防疫

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

基于MATLAB的PEF湍流风场生成器模拟与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于MATLAB的PEF湍流风场生成器模拟与仿真。PEF&#xff08;Primitive Equations Formulation&#xff09;湍流风场模型&#xff0c;是大气科学和气象学中用来描述大气流动和气…

WebOffice在线编微软Offfice,并以二进制流的形式打开Word文档

在日常办公场景中&#xff0c;我们经常会遇到这种场景&#xff1a;我们的合同管理系统的各种Word,excel,ppt数据都是以二进制数组的形式存储在数据库中&#xff0c;如何从数据库中读取二进制数据&#xff0c;以二进制数据作为参数&#xff0c;然后加载到浏览器的Office窗口&…

【已解决】腾讯云安装了redis,但是本地访问不到,连接不上

汇总了我踩过的所有问题。 查看配置文件redis.conf 1、把bind 127.0.0.1给注释掉&#xff08;前面加个#就是&#xff09;或者改成bind 0.0.0.0&#xff0c;因为刚下载时它是默认只让本地访问。&#xff08;linux查找文档里的内容可以输入/后面加需要匹配的内容&#xff0c;然后…

2024人工智能大会_强化学习论坛相关记录

求解大规模数学优化问题 规划也称为优化 四要素&#xff1a;数据、变量、目标、约束 将一个简单的数学规划问题项gpt进行提问&#xff0c;GPT给了一个近似解&#xff0c;但不是确切的解。 大模型的训练本身就是一个优化问题。 大模型是如何训练的&#xff1f;大模型训练通常使…

Unity通过NDK实现C#与C++之间的相互调用

由于一些历史遗留问题&#xff0c;我们项目还在使用一套C实现的Box2D定点数的库&#xff0c;由于最近修改了视野算法所以需要重新打包安卓的【.so】文件&#xff0c;特此记录 1、关于NDK 在Android平台&#xff0c;C/C需通过NDK编译成动态链接库.so文件&#xff0c;然后C#中通过…