C语言第21讲

整数在内存中的翻译

整数的二进制表示方式有3种,即原码,反码,补码

在内存中存放的是补码

类型存入翻译和类型取出翻译,数据存储方式和数据取出方式,都是同操作流程的相反顺序

在讲翻译前需要引入个概念 符号位

符号位表示的就是 数据在正负符号

例如:9 其实是 +9 (常常省略+号) -9

所以在32个比特位最前方一位表示为符号 0正 1符负

现讲,整形类型的翻译方式

整形的翻译方式会根据,整形的正负数分两类

正数:

正数的原码是本身的二级制

正数特殊的点在于 原码 反码 补码 都相同

例如:1的2进制(int为4字节,有32个比特位)

0 0000000 00000000 00000000 00000001

负数:

负数的原码也是本身二进制**(正负原码翻译的没区别)**

反码为 符号为不变,其它位0变1,1变0

补码为 在反码的基础上+1

例如:-1的全流程图如下

负数取出数据就是 -1 再 符号位不变 0变1,1变0;只不过顺序流程倒置而已

不过取出 将补码 符号位不变 0变1 1变0 再+1也能得到原码

注意上面说的是两个方式,选一个就可以得到原码

数据在内存中的存放

我们常常会发现,数据在内存中存放是按比例反向的

我们去观察以下代码在内存中单存放

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>

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

能发现,这里的存放是按字节为大小,反向存放着。这样的存放方式就叫做小端字节序

大小端字节序

其实超过一个字节的数据在内存中存储的时候,就会有存储顺序的问题。按照不同的存储顺序,我们分为大端字节序和小端字节序存储

字节序存储 按照一个字节一个字节的大小分开数据,按某种顺序存储

这个顺序的分辨在与小端和大端

小端字节序:

将低位字节的内容存储到低地址处,高位字节的内容存储到高地址处

例如:

123 可以分出 个位3 十位2 百位1

个位低位 百位为高位

而数据会翻译成补码

再以一个字节大小分出高低位,分别存放

大端字节序:

讲低位字节内存存储到高位地址处,高位字节序内容存储到低地址处

**问题:**设计一个小程序来判断当前机器的字节序

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>

int test()
{
	int a = 1;
	char* p = &a;
	return *p;            
}

int main()
{
	if (test() == 1)
		printf("小端");
	else
		printf("大端");
	return 0;
}

题目2:

cpp 复制代码
#include <stdio.h>
 int main()
 {
 char a= -1;                            // -1 VS. char是signed char 这个取决于编译器
 signed char b=-1;                      // -1 
 unsigned char c=-1;                    // 255
 printf("a=%d,b=%d,c=%d",a,b,c);
 return 0;
 }
cpp 复制代码
 unsigned char c=-1;                   
 printf("%d",c);

结果为255的过程如下图判断

问题3:

cpp 复制代码
 #include <stdio.h>
 int main()
 {
 char a = -128;
 printf("%u\n",a);        // 4294967168 
 return 0;                // 11111111 11111111 11111111 10000000
 }

问题4:

cpp 复制代码
#include <stdio.h>
 int main()
 {
 char a = 128;
 printf("%u\n",a);        // 4294967168 
 return 0;                // 11111111 11111111 11111111 10000000
 }                       

128和-128在截取时都是1000 0000 后续操作一样值一样

问题5:

cpp 复制代码
#include <stdio.h>
 int main()
{
char a[1000];
 int i;
 for(i=0; i<1000; i++)
 {
 a[i] = -1-i;
 }
 printf("%d",strlen(a));        // 255 
 return 0;
}

这里有个结论图:

问题5:

cpp 复制代码
 #include <stdio.h>
 //X86环境 ⼩端字节序
 
int main()
 {
 int a[4] = { 1, 2, 3, 4 };
 int *ptr1 = (int *)(&a + 1);
 int *ptr2 = (int *)((int)a + 1);     // 0x00 00 00 04   0x 02 00 00 00
 printf("%x,%x", ptr1[-1], *ptr2);    // 4               2000000
 return 0;
 }

浮点数在内存中的存储

任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式

V = (-1)^S * M * 2^E

• (-1)^S 表⽰符号位,当S=0,V为正数;当S=1,V为负数

• M表⽰有效数字,M是⼤于等于1,⼩于2的

• 2^E 表⽰指数位

举例来说:

⼗进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2

那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2

观察上方式子可以发现,(-1) 和 2是固定常数,变化的位 S M E 三数所以存储只需要储存S M E 就好了

在存储 S M E 3数时还需要注意2点:

1.由于 M 数 总是会变化成 1.xxxx的数,范围在(1,2)之间

所以再存储时可以将1.xxxx的1不进行存储,在有效位存储时会多出1位

2.将举例改为0.5时会发现E 会出现负数情况,所以 E在存储时会根据类型的不同做出一下措施:

1.32位 E+127(中间值)

2.64为 E+1023(中间数)

这中间数和E在内存中存储的内存空间大小相关

现在储存内容弄清后,接下来就是每个内容有多大存储空间

由国家标准规定:

32位( float 4字节):

64位( double 8字节)

浮点数取的过程 指数E从内存中取出还可以再分成三种情况:

E不全为0或不全为1 :

这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效 数字M前加上第⼀位的1。 ⽐如:0.5的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其 阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位 00000000000000000000000,则其⼆进制表⽰形式为:

0 01111110 00000000000000000000000

E全为0:

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还 原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字;

  • 这相当于指数被固定为最小的值(-126),然后只通过尾数部分来提供更精细的精度

0 00000000 00100000000000000000000

E全为1:

这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);

0 11111111 00010000000000000000000

问题:

cpp 复制代码
 #include <stdio.h>
 int main()
 {
 int n = 9;
 float *pFloat = (float *)&n;                
 
 printf("n的值为:%d\n",n);                    // 9
 printf("*pFloat的值为:%f\n",*pFloat);        // 0.000000
 
 *pFloat = 9.0;
                                              // 0 1000 0010 001 0000 00000000 00000000 
 printf("num的值为:%d\n",n);                  // 1091567616
 printf("*pFloat的值为:%f\n",*pFloat);        // 9.000000
 return 0;
 }

相关推荐
GilgameshJSS3 小时前
STM32H743-ARM例程10-WWDG
c语言·arm开发·stm32·单片机·嵌入式硬件
程序员大辉3 小时前
python代码案例分享,python实现代码雨,动画显示,pygame使用教程
开发语言·python
jghhh013 小时前
针对大尺度L1范数优化问题的MATLAB工具箱推荐与实现
开发语言·算法·matlab
伊织code4 小时前
python-poppler - PDF文档处理Python绑定库
开发语言·python·pdf·python-poppler
爱上妖精的尾巴4 小时前
5-16WPS JS宏 map数组转换迭代应用-1(一维嵌套数组结构重组)
开发语言·前端·javascript·wps·jsa
HY小海4 小时前
【C++】二叉搜索树
开发语言·数据结构·c++
sali-tec4 小时前
C# 基于halcon的视觉工作流-章38-单位转换
开发语言·人工智能·数码相机·算法·计算机视觉·c#
“愿你如星辰如月”5 小时前
Linux C缓冲区机制全解析
linux·运维·服务器·c语言·vscode
ss2735 小时前
手写MyBatis第78弹:装饰器模式在MyBatis二级缓存中的应用:从LRU到防击穿的全方案实现
java·开发语言