初学者关于数据在内存中的储存的笔记

1.整数在内存中的储存

  • 整数的2进制表⽰⽅法有三种,即 原码、反码和补码
  • 有符号的整数,三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰"正",⽤1表⽰"负",最⾼位的⼀位是被当做符号位 ,剩余的都是数值位
  • 正整数的原、反、补码都相同。 负整数的三种表⽰⽅法各不相同
  • 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
  • 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
  • 补码:反码+1就得到补码。
  • 对于整形来说:数据存放内存中其实存放的是**⼆进制的补码**。

为什么呢?

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

2.大小端字节序

是什么

⼤端(存储)模式:
是指数据的低位 字节内容保存在内存的**⾼地址** 处,⽽数据的**⾼位** 字节内容,保存在内存的低地址处
⼩端(存储)模式:
是指数据的低位 字节内容保存在内存的低地址 处,⽽数据的**⾼位** 字节内容,保存在内存的**⾼地址处**。
上述概念需要记住,⽅便分辨⼤⼩端。

为什么

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8 bit 位,但是在C语⾔中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看 具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。
例如:⼀个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么
0x11 为⾼字节, 0x22 为低字节。对于⼤端模式,就将 0x11 放在低地址中,即 0x0010 中,
0x22 放在⾼地址中,即 0x0011 中。⼩端模式,刚好相反。我们常⽤的 X86 结构是⼩端模式,⽽ KEIL C51 则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。

练习

1.设计一个程序,判断当前机器的字节序

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int check_sys()
{
	int i = 1;
	return (*(char*)&i);
    
}
int main()
{
	int ret = check_sys();
	if (ret = 1)
		printf("小端");
	else
		printf("大端");
	return 0;
}

2.下列代码运行结果是什么

cpp 复制代码
#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;
} 

%d是以十进制的方式打印有符号整数(认为内存中存的是有符号整数的补码)char要进行整型提升。

3.下列代码运行结果是什么

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

%u打印无符号整型,没有符号位

4.下列代码运行结果是什么

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

找0

5.下列代码运行结果是什么

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

死循环

cpp 复制代码
#include <stdio.h>
int main()
{
    unsigned int i;
    for(i = 9; i >= 0; i--)
    {
        printf("%u\n",i);
    }
    return 0;
}

死循环

6.下列代码运行结果是什么

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);
    printf("%x, %x", ptr1[-1], *ptr2);
    return 0;
}

%x以十六进制打印数据,无符号

3.浮点数在内存中的储存

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V = (−1) SM ∗ 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。
IEEE 754规定:
对于32位的浮点数(float),最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字
M
对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效
数字M

3.1浮点数存的过程

IEEE 754 对有效数字M和指数E,还有⼀些特别规定。

3.1.1M

前⾯说过, 1 ≤ M < 2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表⽰⼩数部
分。IEEE 754 规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后⾯的xxxxxx部分。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的⽬的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。

3.1.2E

这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存⼊内存时E的真实值必须再加上⼀个中间数,对于8位的E,这个中间数是127 ;对于11位的E,这个中间数是1023。⽐如, 2 ^ 10 的E是10,所以保存成32位浮点数时,必须保存为0+127=137,即10001001。这样的浮点数存储⽅式很巧妙,但是我们也要注意到有的 浮点数是⽆法精确保存的 。

3.2浮点数取的过程

3.2.1E不全为0或不全为1

E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第⼀位的1。

3.2.2E全为0

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

3.3.3E全为1

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

目录

1.整数在内存中的储存

2.大小端字节序

是什么

为什么

练习

1.设计一个程序,判断当前机器的字节序

2.下列代码运行结果是什么

3.下列代码运行结果是什么

4.下列代码运行结果是什么

5.下列代码运行结果是什么

6.下列代码运行结果是什么

3.浮点数在内存中的储存

3.1浮点数存的过程

3.1.1M

3.1.2E

3.2浮点数取的过程


相关推荐
摇滚侠27 分钟前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 属性优先级 行内写法 变量选择 笔记42
java·spring boot·笔记
摇滚侠31 分钟前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 总结 热部署 常用配置 笔记44
java·spring boot·笔记
rechol1 小时前
汇编与底层编程笔记
汇编·arm开发·笔记
lzj_pxxw2 小时前
嵌入式开发技巧:舍弃标志位,用宏定义函数实现程序单次运行
笔记·stm32·单片机·嵌入式硬件·学习
润 下2 小时前
C语言——回调函数的典型示例(分析详解)
c语言·开发语言·人工智能·经验分享·笔记·程序人生
朝新_2 小时前
【EE初阶 - 网络原理】传输层协议
java·开发语言·网络·笔记·javaee
koo3643 小时前
李宏毅机器学习笔记27
人工智能·笔记·机器学习
峰顶听歌的鲸鱼3 小时前
1.云计算与服务器基础
运维·服务器·笔记·云计算·学习方法
Kay_Liang3 小时前
大语言模型如何精准调用函数—— Function Calling 系统笔记
java·大数据·spring boot·笔记·ai·langchain·tools
bnsarocket4 小时前
Verilog和FPGA的自学笔记7——流水灯与时序约束(XDC文件的编写)
笔记·fpga开发