文章目录
前言
主要讲解了:
- 压栈的基本思想
- 大小端的存储
- 整型 和 浮点型在内存中不同的存储方式
原码 反码 补码
计算机的存储和计算都是用的二级制补码
正数的原码,反码,补码都相同
原码
是数值的二级制形式 例: 10 的二级制为 1010
负数的最高位二级制位为1(表示符号位)
反码
符号位不变,其他位取反(1变成0,0变成1)
补码
在反码的基础上 加上 1
例如 反码为 1010 则补码就是 反码加1 为 1011
从补码转换为真值
- 可以用相反的计算求出真值,补码减一然后再取反
- 可以再进行一次"取反加1"(再进行一次变补码的计算),这样依旧可以变成原来的值,计算机也是采用的这个方式
函数调用的参数压栈
栈是一种数据结构
每一个函数调用都会在内存的栈区上开辟一块空间!
先进的后出,后进的先出(存储从底部开始)
大小端存储(字节存储顺序)
大端存储
把数据的低位字节序内容存放在高地址处
高位字节序的内容存放在低地址处
小端存储
VS2022采用的就是小端存储
把数据的低位字节序内容存放在低地址处
高位字节序的内容存放这高地址处
判断当前程序是大端存储还是小端存储
#include<stdio.h>
void main()
{
int a = 1;
char* p = (char*)&a;
if (*p == 1) printf("小端\n");
else printf("大端\n");
}
数组存储时,应用的大小端
int arr[] = { 1,2,3,4,5 };
short* p = (short*)arr;
int i = 0;
for (i = 0; i < 4; i++)
{
*(p + i) = 0;
}
for (i = 0; i < 5; i++)
{
printf("%d", arr[i]);
}
整型在内存中存储
整型有int,short,char,long以及相关的有符号无符号等
有符号char范围为 -128~127 (8位二进制256种可能)
当赋值超出范围时,负数+256,正数-256
例: char i=-129; i中其实放的是-129+256=127
无符号char范围为 0~255 (8位二进制256中可能)
例1
#include<stdio.h>
void main()
{
char a = -128;
printf("%u\n", a);
}
打印为一个超级大的整数
char类型只能存放一个字节(8比特位),前面的二进制位舍去
先求出-128的补码,然后只取后八位,1000 0000
打印时整型提升,前面全部补符号位,111……1000 0000
%u为无符号整型,正数三码都相同,直接打印出111……1000 0000的十进制数
例2
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
i=0通过后,i还会自减,i==-1
二级制补码为1111………1111
创建i的时候为无符号整型,直接识别-1为正数,正数三码相同
i==超大的正整数 每次i减到-1都会变成这个数,因此造成死循环
例3
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d\n", strlen(a));
char范围为-128~127 当赋值超出范围时,负数+256,正数-256
循环数为:-1 -2 -3 -4 -5…… -128 127 126 125…… 0 -1 -2 -3……
strlen()函数是算出字符实际长度,即\0之前的字符有多少个
找到0就是\0(ASCII码) 0前面一共有128(-1到-128 )+127(1到127 )=255个
浮点型在内存中存储
根据国际标准IEEE(电气和电子工程协会)754
任意一个二进制浮点数V可以表示成下面的关系:(-1)s * M * 2E
存储方式
s :直接在二进制首位放上0或1
M :M的小数点前总是1,所以不记录,只记录小数点后的数,数写前面后面全部补零 如 M1.001 在二进制中是 0010000000000……
E :E为无符号整数,但是E可能为负 如 0.5(十进制) -> 0.1(二进制) -> 1.0*2-1
所以要加上一个中间数,E为8位时,中间数是127 如 -1+127=126转换为二级制存入内容
E为11位时,中间数是1023 如 -1+1023=1022转换成二级制存入内存
例 浮点数 5.5
(-1)0 * 1.011 * 22
s=0 M=1.011 E=2
s=0 M=011 E=2+127=129
0 10000001 01100000……
(内存中是小端存储,40 b0 00 00 -> 00 00 b0 40)
二级制转回十进制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lsQak6HN-1691319736854)(…/素材/进阶_1_3.png)]
E为全零时 规定此时E等于1-127(或者1-1023)
有效数字M不再加上第一位的1,而是还原为0.XXXXXX的小数
这要做视为了表示正负0(无穷小),因为后面小数点限制(保留多少位)会显示出0.000000
E为全1时 表示正负无穷大
printf()中类型如果与参数不符,则可能打印出不是想要的结果
扩展
栈区
栈区与栈不同,局部变量存放在栈区中,如果访问数组跟下面例子一样超出了,则可能造成死循环,i的地址与数组最后一个元素的地址挨在一起,超出到i的地址再赋值就会一直这样循环
VS中存储固定相隔8个字节(在int类型中是两个元素)
c和c++的内存存储
- 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
- 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS(程序)回收。分配方式类似于链表。
- 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 - 代码段:存放函数体(类成员函数和全局函数)的二进制代码。