椋鸟C语言笔记#26:数据在内存中的存储(大小端字节序)、浮点数的存储(IEEE754)

news2024/11/24 19:15:18

萌新的学习笔记,写错了恳请斧正。


目录

大小端字节序

什么是大小端

写一个判断大小端的程序

浮点数在内存中的存储(IEEE 754规则)

引入

存储规则解释

读取规则解释

1.阶码不全为0或全为1(规格化数)

2.阶码全为0(非规格化数)

3.阶码全为1,尾数全为0(inf)

4.阶码全为1,尾数不全为0(非数,NaN,Not a Number)

练习

1.浮点数

2.整型存储

a.下面程序的输出为

b.下面两个程序的输出为

c.下面程序的输出为

d.下面两个程序的输出为

e.下面程序的输出为(假设小端环境)


大小端字节序

什么是大小端

首先,我们要知道,整数(short、int、long、long long)在内存中以补码的形式存储,无符号整数(unsigned)在内存中以原始二进制序列存储。

当数据长度小于等于一个字节时 ,很显然计算机就直接存储在一个字节内(内存存储的基本单元是字节)。而大小端字节序,则是超过一个字节的数据在内存中存储的两种方式。

为了更清楚的理解大小端字节序,下面我们创建一个变量a:

#include <stdio.h>

int main()
{
    int a = 0x12345678;
    return 0;
}

我们知道int整型占4个字节,也就是说12、34、56、78会分别存储在4个字节单元中。那么,这4个字节单元在内存中是从高地址向低地址排列还是由低向高就成了一个问题。

我们把78这一头叫做数据的低位字节,12那一头叫做高位字节。那么:

  • 将数据的低位字节存储在内存的高位,就叫大端存储,对应大端机器
  • 将数据的低位字节存储在内存的低位,就叫小端存储,对应小端机器

下面我们在Visual Stodio(x86 Debug)环境下调试上方代码, 并打开内存窗口,观察变量a的内存空间:

这就是将数据的低位字节(78)储存在了内存的低位,是小端存储模式。

我们常用的大多数环境(x86、x64…)都是小端结构( 有计算优势),但是仍然存在大端模式的机器(如KEIL C51)。甚至有些ARM处理器可以让硬件选择采用大端还是小端。
写一个判断大小端的程序

其实很简单,我们截取数字1在内存中的第一个字节即可。

如果输出是1就是小端机器,如果是0就是大端机器。

#include <stdio.h>

int check_sys()
{
	int i = 1;
	return *(char*)&i;
}

int main()
{
	if (check_sys())
		printf("该机器为小端字节序机器\n");
	else
		printf("该机器为大端字节序机器\n");
	return 0;
}

这里先取a的地址、强制类型转换为char*再解引用来取出a在内存中的第一个字节。

注意:这里不能直接将a强制类型转换为char类型来读取第一个字节,因为这样永远只会截取数据最低位的字节,和大小端机器无关。

或者我们也可以用联合体的方式取第一个字节(联合体相关内容在之后的笔记):

int check_sys()
{
    union
    {
        int i;
        char c;
    } u;
    u.i = 1;
    return u.c;
}

浮点数在内存中的存储(IEEE 754规则)

引入

浮点数包括float、double、long double等类型,可写成小数形式(3.14)或科学计数法(1.1E2)

不同浮点数的数据范围在float.h头文件中被规定

下面我们看一段代码:

#include <stdio.h>
int main()
{
	int n = 9;
	float* p = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*p的值为:%f\n", *p);
	
	*p = 9.0;
	printf("n的值为:%d\n", n);
	printf("*p的值为:%f\n", *p);
	
	return 0;
}

这段代码的输出结果为:

n的值为:9
*p的值为:0.000000
n的值为:1091567616
*p的值为:9.000000

明明n与*p在内存中是同一个数,为什么会出现上方的情况呢?

这与浮点数在内存中的存储有关

存储规则解释

浮点数在内存中的存储遵循IEEE 754规则,由电气与电子工程师协会(IEEE)规定

单精度浮点数为例,我们将其分为3个部分存储在内存中(都是01组成的二进制):

  • 符号位S:1位,0代表正数,1代表负数
  • 阶码E:8位,就是科学计数法的指数部分加127(因为其表示精度的是-126次方到127次方,要加上127让阶码从数字1到254便于存储,因此单精度浮点数也叫余127码)(阶码0与255有特殊含义,见下方读取相关内容
  • 尾数M:23位,就是科学计数法中数字小数点后的部分

以数字5.0为例:

  1. 其为正数,则S=0
  2. 其可以表示成二进制科学计数法1.01*2^2,则尾数M为01000000000000000000000
  3. 其科学计数法指数为2加上127得到阶码E=129=10000001(二进制)
  4. 合起来就能得到数字5.0在内存中的存储:0100 0000 1010 0000 0000 0000 0000 0000

对于双精度浮点数,其规则与单精度浮点数类似,但是阶码变为11位(余1023码),尾数变为52位。总字节数由4字节变为8字节。

读取规则解释

读取时有3种情况:

1.阶码不全为0或全为1(规格化数)

读取时阶码减去127(或1023)得到指数部分,尾数加1得到数字部分

所以说单精度浮点数规格化数的指数范围是-126到127

2.阶码全为0(非规格化数)

读取时阶码加一再减去127(或1023)得到指数部分(加一使浮点数取值连续),尾数不加1,用于表示极其接近0的数字

如果尾数也全为0,则代表浮点数的±0

3.阶码全为1,尾数全为0(inf)

被判定为浮点数的无穷,正负由符号位决定,用代码inf表示

4.阶码全为1,尾数不全为0(非数,NaN,Not a Number)

代码NaN表示,用于表示异常数据(比如某个数除以0就会返回NaN,也有可能输出IND-indeterminate不确定的)

练习

1.浮点数

这时上面浮点数存储开头的那一段代码就好理解了

首先第一部分将整型9当做浮点数输出,整型9在内存中存储为:

0000 0000 0000 0000 0000 0000 0000 1001

将其当做浮点数,则S=0,阶码E=00000000,由上面非规格化数内容我们知道这是一个趋近于0的数,所以输出了0.000000

第二部分将浮点数9.0当做整数输出,浮点数9在内存中存储为:

0100 0001 0001 0000 0000 0000 0000 0000

将其当做整型输出即补码转换为原码为:1091567616

2.整型存储
a.下面程序的输出为
#include <stdio.h>

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;
}

就是很简单的截取,输出a=-1,b=-1,c=255

b.下面两个程序的输出为
#include <stdio.h>

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

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

两个程序的输出结果均为4294967168

也是简单的整型提升的问题

比如第一段程序-128的补码为1111 1111 1111 1111 1111 1111 1000 0000

截取到a为1000 0000,整型提升回1111 1111 1111 1111 1111 1111 1000 0000

其直接二进制转换十进制为4294967168

第二段等价,对于char来说127之上就循环回到-128,所以128与-128在这里没有区别

c.下面程序的输出为
#include <stdio.h>

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

此代码输出为255

同样的,对于char类型,-128在减一就循环回到了127。所以这里就是从-1一直降到-128,在从127降到1(strlen遇到“\0”结束,其ASCII码为0,所以之后的没意义)

d.下面两个程序的输出为
#include <stdio.h>

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

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

这两段代码都是死循环,很简单

e.下面程序的输出为(假设小端环境)
#include <stdio.h>

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);
	return 0;
}

其输出结果为4,2000000(有可能引发读取访问权限冲突)

很好理解,指针1减一指向数组第4个元素,指针2指向第一个元素向后偏移一位字节,也就是略过了数字1内存第一个字节又加上了数字2内存第一个字节。在小端环境下即为0x02000000


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

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

相关文章

代码随想录27期|Python|Day15|二叉树|层序遍历|对称二叉树|翻转二叉树

本文图片来源&#xff1a;代码随想录 层序遍历&#xff08;图论中的广度优先遍历&#xff09; 这一部分有10道题&#xff0c;全部可以套用相同的层序遍历方法&#xff0c;但是需要在每一层进行处理或者修改。 102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; 层…

root登录提示:Access denied

一、问题&#xff1a; 在使用xshell工具用root账号登录服务器时提示Access denied&#xff0c;拒绝访问&#xff0c;SSH服务器拒绝了密码&#xff0c;但用其它用户又可以连接. 二、原因 是因为sshd的设置不允许root用户用密码远程登录的问题 三、解决办法 使用可以登录的账…

Parade Series - Message Interaction

if (true) {Swal.fire("节目发布", "发布完毕", "success");event.preventDefault(); } if (false) {Swal.fire("节目发布", "发布失败", "error");event.preventDefault(); }if (true) {for (var i 0; i < b…

Matlab论文插图绘制模板第130期—函数曲面图

在之前的文章中&#xff0c;分享了Matlab函数折线图的绘制模板&#xff1a; 函数三维折线图&#xff1a; 函数网格曲面图&#xff1a; 进一步&#xff0c;再来分享一下函数曲面图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&a…

DBCA创建RAC的过程截图

以下错误是由于配置的内存较大&#xff0c;而大页&#xff08;HugePage&#xff09;配置较小导致&#xff0c;调整大页后就好了。

Luminar Neo:超强AI图像编辑器,助力你轻松创作完美照片!

如果你是一位热爱摄影和图像编辑的人&#xff0c;那么我相信你一定会喜欢 Luminar Neo&#xff08;超强AI图像编辑器&#xff09;&#xff01;不仅仅是一款普通的图像编辑软件&#xff0c;Luminar Neo融合了人工智能技术&#xff0c;让你在编辑照片时拥有更多可能性和创意。 L…

Python小程序 - 表格数值统计

题设&#xff1a;Excel表格中&#xff0c;计算如下图所示不同颜色&#xff08;蓝、黄、桔&#xff09;单元格值&#xff1a;各颜色填涂的单元格值的总和条件&#xff1a; - Excle表格中 - 分色标记&#xff0c;单元格有值 - 开始列&#xff08;当前为D&#xff09;&#xff0c;…

基于SSM的咖啡销售系统vue论文

摘 要 现代社会是计算机技术普遍发展与应用的社会&#xff0c;甚至无网不成行&#xff0c;由此可见信息网络已经在商家活动或者人们生活中占据非常重要的地位&#xff0c;成为各行业不可割舍的重要组成。而随着网络地位的越来越突出&#xff0c;网络平台已经超越电视、报纸等传…

记一次clickhouse启动报错

clickhouse一次排错 clickhouse启动报错 报错&#xff1a; Application: Code: 210. DB::Exception: Listen [::]:8123 failed: Poco::Exception. Code: 1000, e.code() 0, DNS error: EAI: Address family for hostname not supported (version 23.3.1.2823 (official bui…

新零售ERP软件功能有哪些?新零售ERP系统哪个操作简单

新零售企业通常存在多仓库、多营销渠道、多业务模式、价格策略灵活、供应链复杂等情况&#xff0c;如何实现配送、财务、客户、订单、仓储等业务数据一体化和智能化管理&#xff0c;是不少新零售企业需要解决的难点。 随着新零售企业数量不断增多&#xff0c;行业之间的竞争也…

【Python必做100题】之第十四题(反向输出四位数)

题目&#xff1a;编写程序&#xff1a;输入一个四位整数&#xff0c;反向输出对应的四位数 思路&#xff1a;将整数转化为字符串类型&#xff0c;利用字符串的切片进行逆转输出 代码如下&#xff1a; #编写程序&#xff1a;输入一个四位整数&#xff0c;反向输出对应的四位数…

小间距LED显示屏在会议室的应用

LED显示屏作为自发光显示设备&#xff0c;在其高亮度、远观距离、高对比度和清晰度等特点的推动下&#xff0c;已经成为不可或缺的显示设备之一。随着LED显示屏厂家和整个产业链对产品的不断完善&#xff0c;小间距LED显示屏正逐渐成为会议室中的首选。那么&#xff0c;什么是细…

【深度学习】强化学习(三)强化学习的目标函数

文章目录 一、强化学习问题1、交互的对象2、强化学习的基本要素3、策略&#xff08;Policy&#xff09;4、马尔可夫决策过程5、强化学习的目标函数1. 总回报&#xff08;Return&#xff09;2. 折扣回报&#xff08;Discounted Return&#xff09;a. 折扣率b. 折扣回报的定义 3.…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于乐观行动-评判深度强化学习的含氢综合能源系统低碳经济调度》

这个标题涉及到基于乐观行动的深度强化学习在含氢综合能源系统低碳经济调度方面的评判。让我们逐步解读&#xff1a; 基于乐观行动&#xff08;Optimistic Action&#xff09;&#xff1a; 可能指的是在决策或行动中采取积极、乐观的策略&#xff0c;即在不确定性环境下&#x…

高效排队,紧急响应:RabbitMQ Priority Queue全面指南【RabbitMQ 九】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 高效排队&#xff0c;紧急响应&#xff1a;RabbitMQ Priority Queue全面指南 引言前言第一&#xff1a;初识RabbitMQ Priority Queue插件插件的背景和目的&#xff1a;为什么需要消息优先级&#xff1…

C++ 指针基础

指针的定义 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h>int main() {int a 10;printf("%p\n", &a); // &a 表示取&#xff08;a&#xff09;的地址 000000842FD9FB64// 存放指针&#xff08;地址&#xff09;的变量就是指针变量&#xff0c…

系统运行占用过高

1、CPU过高的问题排查 示例代码&#xff1a; public class Test { static class MyThread extends Thread { public void run() { // 死循环&#xff0c;消耗CPU int i 0; while (true) { i; } } } public static void main(String args[]) throws InterruptedException { ne…

DevOps搭建(十二)-阿里云镜像仓库的使用详解

有时候,不想在服务器自己搭建镜像仓库,那么我们可以使用阿里云镜像仓库,详细使用方法如下。 1、容器镜像服务 阿里云镜像服务地址: https://cr.console.aliyun.com/cn-hangzhou/instances 选择个人实例 2、创建命名空间 3、创建镜像仓库 考虑到安全性,仓库类型选择我…

【贝叶斯分析】计算机科学专业博士作业二

1 第一题 1.1 题目 已知变量A和B的取值只能为0或1&#xff0c;A⫫&#x1d469;&#xff0c;且&#x1d45d;(&#x1d434;1)0.65&#xff0c;&#x1d45d;(&#x1d435;1)0.77。C的取值与A和B有关&#xff0c;具体关系如下图所表&#xff1a; ABP(C1|A,B)000.1010.99100…

使用Pytorch从零开始构建StyleGAN2

这篇博文是关于 StyleGAN2 的&#xff0c;来自论文Analyzing and Improving the Image Quality of StyleGAN&#xff0c;我们将使用 PyTorch 对其进行干净、简单且可读的实现&#xff0c;并尝试尽可能地还原原始论文。 如果您没有阅读 StyleGAN2 论文。或者不知道它是如何工作…