系列文章目录
第一章 汇编指令以及堆栈概念
前言
分析代码经常用到汇编指令,下面列出常用的指令,足够应付一般情况,之后会慢慢补充
一、常用汇编指令
LDRB:读一个字节
LDRH:读两个字节
STRB:写一个字节
STRH:写两个字节
PSR:program status register程序状态寄存器
数据传送指令
MOV dest, src 将数据从src移动到dest
PUSH src 把源操作数src压入栈(进栈指令)
POP desc 从栈顶弹出字数据到dest(出栈指令)
二、内存
1.C语言中内存分配的方式有几种?
1)静态存储区分配
内存分配在程序编译之前完成,且在程序的整个运行期间都存在,例如全局变量、静态变量等。
2)栈上分配
在函数执行时,函数内的局部变量的存储单元在栈上创建,函数执行结束时这些存储单元自动释放
3)堆上分配
这段代码实现了一个非常简单的内存分配函数 my_malloc。它使用一个固定大小的缓冲区 heap_buf 来分配内存,而不是使用系统提供的内存分配函数(如 malloc)。
char heap_buf[1024]; // 声明一个大小为1024字节的缓冲区
int pos = 0; // 初始化一个位置指针,指向缓冲区的起始位置
void *my_malloc(int size) // 定义一个函数 my_malloc,用于分配指定大小的内存,返回类型是 void *,表示返回一个指向分配内存的指针。
{
int old_pos = pos; // 保存当前的位置指针
pos += size; // 将位置指针向前移动 size 字节
return &heap_buf[old_pos]; // 返回缓冲区中旧位置的地址(即分配的内存起始地址)
}
这个 my_malloc 函数可以用于分配内存,但它没有任何错误检查机制,也没有释放内存的功能。使用这个函数时需要确保分配的内存不会超过 heap_buf 的大小(1024字节),否则会发生越界访问。
例如:char *p = (char *)my_malloc(100); // 分配100字节的内存
这样,p 将指向 heap_buf 中前100字节的起始地址。以后再调用 my_malloc 分配内存时,新的内存块将从 heap_buf 的第101字节开始。
释放内存free,根据头部结构体信息(分配堆时,就会创建一个头信息和100字节),由于系统是用链表来存储空闲内存地址的,自然是不连续的,所以结构体会包含堆字节大小int size、下一个头部结构体地址 struct head *next_free
2.堆和栈有什么区别?
1) 申请方式
栈的空间由操作系统自动分配/释放,堆上的空间手动分配/释放。
2)申请大小的限制
栈空间有限。在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是 一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小
堆是很大的自由存储区。堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
3.)申请效率
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便
3.栈在C语言中有什么作用?
1)C语言中栈用来存储临时变量,临时变量包括函数参数和函数内部定义的临时变量。函数调用中和函数调用相关的函数返回地址,函数中的临时变量,寄存器等均保存在栈中,函数调动返回后从栈中恢复寄存器和临时变量等函数运行场景。
2)多线程编程的基础是栈,栈是多线程编程的基石,每一个线程都最少有一个自己专属的栈,用来存诸本线程运行时各个函数的临时变量和维系函数调用和函数返回时的函数调用关系和函数运行场景。 操作系统最基本的功能是支持多线程编程,支持中断和异常处理,每个线程都有专属的栈,中断和异常处理也具有专属的栈,栈是操作系统多线程管理的基石。
4.C语言函数参数压栈顺序是怎样的?
从右至左。
C语言参数入栈顺序的好处就是可以动态变化参数个数。自左向右的入栈方式,最前面的参数被压在栈底。除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反。因此,C语言函数参数采用自右向左的入栈顺序,主要原因是为了支持可变长参数形式。
总结
`以上就是今天的内容