2. 信息在计算机中存储的格式

news2025/7/18 8:38:46

目录

一、信息存储:

1. 空间大小定义

2. 不同进制的转换方法

3. 各种数据类型所占字节数

4. 字节顺序

5. 字符串存储

6. 代码的二进制表示

7. 布尔代数运算

8. 逻辑运算

9. 移位运算

二、 整数表示

1. 有符号与无符号表示

1.1 表示范围

1.2 补码编码的有符号数

1.3 无符号数

2. 无符号数与有符号整数之间的转换

3. 扩展数字位数与截断数字位数

3.1 位数扩展

3.2 位数截断

三、整数运算

1. 加法

1.1 无符号数加法

1.2 有符号数加法

1.3 加法逆元(无符号数求反、有符号数求非)

2. 乘法

四、浮点数

1. 二进制表示的限制

2.IEEE表示形式

3. 舍入

3.1 实数舍入到浮点数

3.2 float与int之间的转换

4. 浮点数运算


主要介绍C语言中有符号整数(以补码形式表示)、无符号整数浮点数的二进制机器代码表示,以及它们各自的算术运算(包括加减乘除与算术移位)与逻辑运算(与或非与逻辑移位)。以及整数之间转换时、舍入时、溢出时的情况。

一、信息存储:

1. 空间大小定义

字节:8位,是最小的可寻址内存地址。

字长:每台计算机的字长,指明了指针数据的标称大小,也决定了虚拟地址空间的最大值。对于w位的机器而言,最多访问2^w个字节。如32位机器可访问2^32=4,294,967,296Byte≈4G字节,即4GB。64位可访问约16EB。(使用gcc编译时,带上参数-m32可使代码能同时在64位与32位机器上运行,而-m64的代码只能在64位机器上运行。)

2. 不同进制的转换方法

一般的十进制转十六进制、二进制,用商一直除16、2,将余数倒排:

当十进制为2的非负整数n次幂时,转十六进制可以套用公式,n=i+4j,十六进制为1(i=0)、2(i=1)、4(i=2)或8(i=3)后面接j个0。如2048=2^11,n=11=3+4*2,十六进制则为800。

这种方式十六进制不可能以3、f等开头,如0xF0,二进制为11110000=2^4+2^5+2^6+2^7 =240≠2^22,240不是2的整数幂。所以如果一个数是2的幂,用16进制标识第一位只能是1/2/4/8。

3. 各种数据类型所占字节数

数据类型占的内存大小与操作系统和编译器有关,每个编译器都可以为自己的硬件自由选择合适的大小,只受以下限制:short和int至少为16位,long至少为32位,short不长于int,int不长于long。

对于当今的主流编译器,C的各种数据类型占字节数如下:

对于前面加上Unsigned关键字的类型,所占字节数不变。

布尔类型:C中没有bool类型,但是C++中有,虽然理论上bool类型只需要占1位,但因为字节是最小寻址内存地址,所以C++中的bool类型实际上和char一样占1个字节,如何在C中使用或定义bool类型,参考资料:C语言中的bool类型_热带巨兽的博客-CSDN博客_c bool类型;java中如果boolean类型是单独使用的话,编译器会将其转换为int,占4个字节,如果是以数组方式使用的话,则会将其转换为byte数组。为什么单独使用是转换成int,而不转换成byte呢?可以参考:Java中的boolean类型到底占用多少个字节?_WQ同学的博客-CSDN博客_java布尔类型占用多少字节。

本文使用Linux64的情况,即long类型与指针均占8字节。

C语言与编译器维护着数据类型,但编译器生成的机器级程序并不包含数据类型的信息。

4. 字节顺序

大端法:将表示一个数字的字节正序存储(其实是字节的高位存在内存的地址的低位)。小端法:将表示一个数字的字节逆序存储。如十六进制值0x01234567,在内存中存储的顺序如下图所示:

大部分机器都是使用小端法,小端法在对数据进行位数扩展与截断时不会改变改数据在内存的地址,比如将上述Int类型转为short(位数截断),如果使用小端法,short的地址还是0x100,而大端法的地址则会变为0x102。扩展同理。(参考:为什么大部分cpu要做成小端模式,一定要这么做吗? - 知乎为什么大部分cpu要做成小端模式,一定要这么做吗? - 知乎)

但java虚拟机与网络字节序列都是用的大端法。在网络上传输数据时,为保证所有机器能正确处理接收的数据,发送方需要在传输前将数据都转换成统一字节顺序的规则,接收时各机器再转换成自己的字节顺序。

5. 字符串存储

字符串被编码为一个以null(十六进制为00)结尾的字符数组,每个字符以标准编码来表示(一般是ASCII码),字符串不会随机器的字节顺序改变。

6. 代码的二进制表示

由于不同的机器有不同的指令集,以及对指令的二进制编码不同,所以可执行二进制文件不能跨平台运行。

7. 布尔代数运算

布尔代数包括~ & | ^,其中|对&具有分配律,就像乘法对加法具有分配率:a | (b & c)=(a | b) & (a | c)。

a^a=0,即对于^,每个数的逆元是其本身,该操作通常用于将一个寄存器清0。

一个二进制序列可以作为一个mask,如网络IP中的掩码。将mask&目标码,可以使目标码上只有指定位置有效。要生成一个形如0……01……1的mask,采用式子1<<k-1。

8. 逻辑运算

逻辑运算包括&& || !,逻辑运算认为所有非0的参数都为true,返回1(只有字节的最后一位生效)。与布尔代数不同,对于&&或者||,如果第一个参数就能确定结果,那么就不会计算第二个参数。

9. 移位运算

1) 逻辑右移:在左边补0;算术右移:在左边补符号位,基本上所有机器和编译器都对C语言中的有符号数使用算术右移。而Java中,>>表示算术右移,>>>表示逻辑右移。

2) 左移:在右边补0。

3) 当移位的位数超过数字本身的位数时:

三个值的结果分别表示移位了0、4和8:

4) 加减法的优先级比移位运算高

二、 整数表示

1. 有符号与无符号表示

1.1 表示范围

64位程序上C语言中常见数据类型的表示范围:

1.2 补码编码的有符号数

(1)Java中的整数与几乎所有机器上的C中的有符号数使用补码编码,其中负数比正数多一位,1000 0000表示最大负数,0111 1111表示最大正数,0000 0000表示0,1111 1111表示-1(在无符号数中为最大正数)。

(2)一个补码编码的二进制负数转为十进制:

以11011为例:1011=-1*2^4+1*2^3+0*2^2+1*2^1+1*2^0=-5

-x的补码表示可以使用2^w-x计算。如x=6时,2^3-6=2,2=10(BIN),-6=110(BIN)

(3)对于有符号数的下限,在程序中使用-2147283647-1表示,而不直接写为-2147283648,因为当编译器遇到-X时,会先确定X的类型与大小,然后再取负,但是2147283648是C不能使用int类型表示的大正数,所以会将其转换为long long 类型或者unsigned int类型后再取负。

(4)反码在现在机器中几乎不用。原码会在浮点数中使用,原码的最高位决定其他位应该取正权还是负权,如,1010=-2^1=-2,且以0000 0000表示+0,1000 0000表示-0。

(5)补码的加减法,补码的加法与十进制加法类似,该进位进位,该借位借位;而y-x,则求-x值的补码表示(求一个十进制负数的补码,可求其原码取反加一),再做加法y+(-x),高位直接舍弃。参考:补码的加减法运算_不去上课的博客-CSDN博客_补码加法

1.3 无符号数

除了C语言,很少有其他语言支持无符号数,应该少使用C语言的无符号数。除非我们将这些字节整体不看做一个数,而是看做掩码,或者多个bool值的集合等,不可能涉及数据类型转换时,可以使用无符号数。

2. 无符号数与有符号整数之间的转换

机器在执行类型转换时,位上的0与1不会因为数据类型而更改,只是改变了C编译器解释这些位的方式。

1)有符号数→无符号数:

对于负数,一个字节的有符号解释的相反数与无符号解释之和为2^w,如十六进制为0xCFC7的16位为模式即是-12345的补码表示,又是53191的无符号表示,而12345+53191=65536=2^16。即T2U(x)=2^w+x,如T2U(-3)=16+(-3)=13。

对于非负数:T2U(x)=x

2)无符号数→有符号数:

对于x<2^(w-1)的数,U2T(x)=x;

对于x≥2^(w-1)的数,U2T(x)=x-2^w。

3) 在C语言中,存在隐式类型转换,当有符号数与无符号数同在一个表达式中,编译器会将有符号数隐式转换为无符号数进行计算。这样的话,对于<、>、==等比较运算符来说,会出现反直觉的结果,如-1<0U,因为0U为无符号数,-1将被转换为UMAX(最大的无符号数),所以结果为false。

3. 扩展数字位数与截断数字位数

3.1 位数扩展

无符号数为左边添0扩展,有符号数为左边添符号位扩展(类似于算术右移时,左边的位变化)

注意有符号负数左边添符号位扩展不影响数值大小:1000=-2^3,1111 1000=-2^7+2^6 +2^5+2^4+2^3=-2^3。

将short转换成unsigned int时,先对位数进行扩展,在从int转换为Unsigned。

3.2 位数截断

C语言中把Int转换为short时,会对字节的前k位进行位数截断。论字节顺序是大端小端,截掉的位是一样的,但大端法会导致截断后变量在内存的地址发生改变。

对于w位的无符号数,截断前面k位,就保留后面w-k位;对于w位的有符号数,截断前面k位,可能会影响值的正负。

三、整数运算

1. 加法

对于w位的两个数的加法,有时需要w+1位才能保存结果,但是C不会为其分配w+1位,所以当需要w+1位时,C会进行位数截断。

1.1 无符号数加法

(x+y)mod(2^w)为C得到的结果,即只留下w位,舍弃溢出的w+1位。

如何判断结果是否溢出而被截断了?当溢出时,result舍去了最高位,相当于是减了2^w,那么result一定将小于x与y。

1.2 有符号数加法

当x+y正溢出时,符号位的2^(w-1)被溢出为1,解释为-2^(w-1),一去一回相差2^w,所以结果为x+y-2^w;

当负溢出时,溢出的位置一定为1,符号位一定为0,因为11……与01……(第二个1为符号位)都相当于1……(第一个1位符号位),溢出的位被舍弃,所以结果为x+y+2^w。如-14的补码为10010,在4位补码的表示,0010,权值为-2^w的1被舍弃。

如何判断结果是否溢出而被截断,只有当x、y符号相同时,才可能溢出,当结果与x/y相反时,出现溢出。

1.3 加法逆元(无符号数求反、有符号数求非)

即-x,一个数与它的加法逆元相加为0。

无符号数的逆元-x=2^w-x,0的逆元为0。

有符号数的逆元为-x。TMIN的逆元为其本身。

任何整数的-x=~x+1(~x为按位取反,或称为补)。

2. 乘法

(1)同加法一样,无符号数乘法也是截断位数,只留下后面的w位,所以x*y=(x*y)mod (2^w);

有符号数的乘法是先截断留下w位,再将剩下的w位翻译成补码,x*y=U2T((x*y)mod(2^w))

(2)当乘法溢出时,无符号数与有符号数如果乘数的位都相同,乘积截断前的位不同,但是截断后的位都会相同,如:

(3)因为机器在执行乘法时比较慢,所以程序中出现乘以常数时,编译器通常使用移位与加法组合来替代乘法,如3a=(a<<1)+a。

除法比乘法更慢,编译器使用右移来实现除以2的幂,不论是正还是负,结果都会向下舍入(舍去的右边的1,其权值都为正,降低了整个被除数,导致结果偏小)。

有符号整数与无符号整数的计算对比:

有符号整数由于溢出时会导致符号位被淹没,所以结果的正负可能是错的。

四、浮点数

1. 二进制表示的限制

二进制小数,其小数点前每位的权值是2^m,小数点后的权值是2^(-m)。正如不能用十进制小数准确地表示出1/3一样,二进制小数也有一些不能准确表示的值,如1/5。二进制只能准确地表示能被写为x*2^y的数,即对于范围内的部分整数也不能准确表达。在数轴上表示为小范围内均匀,大范围内越靠近0越稠密:

2.IEEE表示形式

(1)IEEE浮点表示为V=(-1)^s*M*2^E

s:符号位,为0或1;

E:阶码,可能为负数。

M:尾数,二进制小数,依赖于e是否等于0。

C语言中float类型E为8位,M为23位;double类型E为11位,M为52位。

(2)浮点数分为几种情况:

1)e既不为全1也不为全0,阶码E为二进制e-Bias,Bias=2^(k-1)-1,之所以要减bias,是为了使幂的范围覆盖正负(-126~127)。如,阶码二进制e为0000 0110,则阶码E为6-(128-1)=-121。尾数M隐含地以1开头(这样可以省一位),只表示小数部分。

整数12345的二进制为0……011000000111001,而12345.0的二进制为0100011001000000 11100100……,两者加粗部分相同,而前者多了一个1,这就是float类型隐藏的默认的1。

2)e为全0时,阶码E为1-Bias(即-126),而尾数不隐含以1开头(这样可以保证可表达的数与第一种情况平滑相接)。此时,当s为1时表示-0.0,当s为0时,表示+0.0。

3)e为全1,当M为全0时,s为1表示负无穷,s为0表示正无穷,可以在溢出时用到。当M不为全0时,表示NaN,如根号(-1)。

3. 舍入

3.1 实数舍入到浮点数

因为程序员可能输入浮点型不可表示的数值,如0.2,这时,机器会使用最接近的浮点数来表示该值,这就是舍入。对于两个浮点可以表示值的正中间,IEEE提供了向0舍入(从浮点数转为int类型时采用)、向上舍入、向下舍入和向偶数舍入(即最后一位为0,默认使用这种,因为不会造成统计学上的偏差)。

3.2 float与int之间的转换

int→float:数字不会溢出,但会舍入(向偶舍入)。不会溢出是因为,虽然float只有23位表示精度,而int有32位表示精度,但是因为float有指数,所以整体范围更大。

float→int:会溢出与舍入(向零舍入)。

4. 浮点数运算

浮点数的加法、乘法是可交换但不可结合的,因为一些情况的结合相较于没结合,会导致中间结果的舍入(或者原来会舍入,而结合后不会舍入),从而影响最终结果,如(3.14+1e10)-1e10会导致3.14被舍入,结果为0.0;而3.14+(1e10-1e1 0)不会引起舍入,结果为3.14。

另外,浮点的乘法不对加法具有分配性,如1e20*(1e20-1e20)=0,而1e20*1e20-1e20*1e20 =NaN(相当于正无穷-正无穷)。

浮点数与整数的计算对比:

计算机整数(包括有、无符号)的算术运算与逻辑运算满足数学上该有的结合律与交换律。而浮点数不满足结合律,因为浮点数表示的精度有限,可能导致中间结果舍入(或者该舍入却没舍入)。

但因为浮点数的溢出会表示为正无穷与负无穷,所以计算结果的正负始终是对的,而有符号数溢出会导致结果符号相反。

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

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

相关文章

C语言日记 35 拷贝构造函数

书P132&#xff1a; 拷贝构造函数的作用是 用已存在的对象初始化另一对象&#xff0c;两对象类类型应一样 在这里我们可以看到&#xff0c; 他对被拷贝的对象的要求只有“已存在的对象&#xff0c;两对象类类型一样”&#xff0c;也就是说他这里也没有说我们不能跨区域&…

使用 Spring Cloud Loadbalancer 实现客户端负载均衡

使用 Spring Cloud Loadbalancer 实现客户端负载均衡 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;使用 Spring Cloud Loadbalancer 实现客户端负载均衡 CSDN&#xff1a;使用 Spring Cloud Loadbalancer 实现客户端负载均衡 背景 在Spring Cloud G 版…

为什么 think-cell 图表中的标签显示为白色矩形?

有些标签的背景错误地变成白色&#xff0c;或显示幻灯片背景。当前版本的 PowerPoint 不会出现此问题。 •使用 PowerPoint 2007 打开 .ppt 文件并单击标签内部时&#xff0c;将显示正确的标签背景&#xff0c;但是在保存后重新打开该文件时&#xff0c;会返回不正确…

分布式系统的 38 个知识点

天天说分布式分布式&#xff0c;那么我们是否知道什么是分布式&#xff0c;分布式会遇到什么问题&#xff0c;有哪些理论支撑&#xff0c;有哪些经典的应对方案&#xff0c;业界是如何设计并保证分布式系统的高可用呢&#xff1f; 1. 架构设计 这一节将从一些经典的开源系统架…

5G无线技术基础自学系列 | 物理随机接入信道

素材来源&#xff1a;《5G无线网络优化实践》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 PRACH信道用于传输前导Preamble序列。gNB…

逆向-破零64位版本

// 排版有点乱&#xff0c;没有图片直观。 #include <stdio.h> #include <stdlib.h> #include <string.h> int f_14a2(int *va, int vb) { /*14a2: f3 0f 1e fa endbr64 14a6: 55 push %rbp 14a7:…

[附源码]java毕业设计基于Web的美食网站的设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【背景渐变】 —— 就算没接触过也能 一遍学会哦

前期回顾 ​回顾 前期 把你喜欢css动画嵌入到浏览器中 —— css动画 项目_0.活在风浪里的博客-CSDN博客常用酷炫动画999合集&#xff0c;代码直接复制可用&#xff0c;总用你想找的&#xff0c;快来抱走吧&#xff0c;三连&#xff0c;停&#xff01;听鹅说&#xff0c;下…

2009年408大题总结

2009年408大题第41题第42题第43题第44题第45题第46题第47题第41题 这个最容易想到的方法就是举反例&#xff0c;但是我们可以分析一下&#xff0c;每一次都取最短的路径&#xff0c;实际上就是贪心策略的应用——每次都是最优&#xff0c;但是最终的结果却一般不是最优&#xf…

第十一节:抽象类和接口【java】

目录 &#x1f947;1. 抽象类 &#x1f4d8;1.1 抽象类概念 &#x1f4d2;1.2 抽象类语法 &#x1f4d7; 1.3 抽象类特性 &#x1f3f9;2. 接口 &#x1f4d9;2.1 接口的概念 &#x1f4d5;2.2 语法规则 &#x1f4d2;2.3 接口使用 &#x1f50e;2.3.1USB接口例子 &a…

【Google Colab】使用手册、教程;使用 Google Colab 免费使用 python 服务器

Colaboratory 是一个 Google 研究项目&#xff0c;旨在帮助传播机器学习培训和研究成果。它是一个 Jupyter 笔记本环境&#xff0c;不需要进行任何设置就可以使用&#xff0c;并且完全在云端运行。Colaboratory 笔记本存储在 Google 云端硬盘中&#xff0c;并且可以共享&#x…

超详细图解kafka生产消费流程

目录&#xff1a; 一条消息在kafka是如何生产的&#xff1f; 一条消息在kafka是如何存储的&#xff1f; 一条消息在kafka是如何消费的&#xff1f; Kafka为什么高性能&#xff1f; Kafka为什么高可用&#xff1f; 一&#xff0e;一条消息在kafka是如何存储的&#xff1f; …

【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由

文章目录目标代码0.动态地显示菜单&#xff1a;store1.动态注册路由2.解决刷新后摆平问题总代码本篇修改的代码文件tab.js参考视频&#xff1a; VUE项目&#xff0c;VUE项目实战&#xff0c;vue后台管理系统&#xff0c;前端面试&#xff0c;前端面试项目案例链接【前端】VueEl…

spring-IOC理论推导P3

1.新建一个项目。名字叫做spring-study 2.导包 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version></dependency></dependencies&…

solr-7.7.3 搭建

solr-7.7.3 搭建 solr-7.7.3 搭建 文章目录solr-7.7.3 搭建一、前期准备安裝规划(一)资料下载(二)上传文件二、安裝(一)创建新用户(二)安装solr1.solr安装包解压到/opt/module2.将解压文件名修改为solr3.修改配置文件(三)分发文件&#xff08;四&#xff09;开启solr&#xff…

YOLOv5量化调优

目录 一、背景 二、模型调优 2.1 基准选取 2.1.1 官方精度数据 2.1.2 fp32bmodel的精度 2.1.3 int8bmodel精度数据 2.2 多图量化 2.3 预处理对齐&lmdb 2.4 网络图优化 2.4.1 per_channel优化 2.4.2 accuracy_opt优化 2.4.3 conv_group优化 2.4.4 总结 2.5 混…

python中使用xlrd、xlwt操作excel表格详解

最近遇到一个情景&#xff0c;就是定期生成并发送服务器使用情况报表&#xff0c;按照不同维度统计&#xff0c;涉及python对excel的操作&#xff0c;上网搜罗了一番&#xff0c;大多大同小异&#xff0c;而且不太能满足需求&#xff0c;不过经过一番对源码的"研究"&…

移动电源出口美国和欧盟需要做什么?

手机的普遍使用也带动了充电宝的发展&#xff0c;现在是智能的时代&#xff0c;手机现在是我们每个人永远不会忘记带的东西&#xff0c;当然耗电量也是很大的。所以充电宝在这时就有很大的用处了。移动电源是一种集供电和充电功能于一体的便携式充电器&#xff0c;一般由锂离子…

杰理的蓝牙芯片的key是什么?以及该如何添加key?杰理key文件原理

目录 一、简介 关于杰理芯片的key文件&#xff0c;实际上 杰理芯片特有的一种机制&#xff0c;而这种机制就是存在于杰理芯片特有的架构&#xff0c;也是杰理公司延续将近10年的特点&#xff0c;估计以后也会是这种机制。具体为什么&#xff0c;请听我娓娓道来&#xff0c;这里…

测试大咖漫谈如何搞定软件质量?

关于质量保障&#xff0c;好像已经说过太多&#xff0c;但这里还是抽象的唠叨几句。 多年的软件测试和质量保障工作让我越来越清晰的认识到&#xff1a;质量绝对不是一个环节&#xff0c;一个工种可以搞定的。比如&#xff1a; 从对语言的误用&#xff0c;到对第三方组件的误用…