高级C语言教程-存储器和指针

ATPCS即ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)的简称

回调函数
通常情况下函数的调用是用户的函数调用操作系统的函数,上层的函数调用底层的函数,而所谓的回调是是指操作系统来调用用户编写的函数,或者底层的函数调用上层的函数。
由于操作系统的代码在用户代码之前就已经完成编译,因此操作系统发起的回调一般由用户编写的函数的函数指针传递给操作系统再由操作系统实现回调。
正如嵌入式的函数的中断等事件的函入口就是采用的回调函数的机制。
多线程
将函数的指针传进负责建立多线程的API中。在一个任务系统中,每个任务从本质上来讲可以理解为是一个拥有自己独立堆栈的函数,在用户需要创建一个新的任务或线程的时候,需要调用由操作系统提供的API 函数(系统调用)。
在函数中实现讲一个数值转换为字符串,相当于sprintf的使用,但是经常使用自己定义的函数当然能够加强自己对于语言的进一步的了解,并且久而久之就自己能够熟练的写出一首很好的代码。

//UnsToStr -- 将一个无符号值转换为字符串
void UnsToStr(unsigned u,char *str)
{
    char *sreStart = str;
    do
        *str++ = (u % 10) + '0';
    while((u/=10)>0);
    *str = '\0';     //在结束的时候加上这样才能使用的字符串确认结尾否则将不是一个完整的字符串
    RenerseStr(strStart);
}
//C语言标准库函数strcpy的一种典型的工业级的最简实现。
//返回值:目标串的地址。
//对于出现异常的情况ANSI-C99标准并未定义,故由实现者决定返回值,通常为NULL。
//参数:des为目标字符串,source为原字符串。
char* strcpy(char* des,const char* source)
 
{
 
     char* r=des;

      assert((des != NULL) && (source != NULL));

     while((*r++ = *source++)!='\0');

     return des;
 
}
//while((*des++=*source++));的解释:赋值表达式返回左操作数,所以在赋值'\0'后,循环停止。
strcpy的实现代码

char * strcpy(char * strDest,const char * strSrc)

{
    if ((NULL==strDest) || (NULL==strSrc)) 
    //[1]
    throw "Invalid argument(s)"; 
    //[2]
    char * strDestCopy = strDest; 
    //[3]
    while ((*strDest++=*strSrc++)!='\0'); 
    //[4]
    return strDestCopy;
}

利用堆栈保存函数调用的返回地址(对于中断处理程序还包括程序状态字寄存器)

大家都知道堆栈的这个功能,当函数调用或者中断发生的时候,返回的地址会自动的压入当前堆栈中(对于ARM处理器而言,这个过程不是由硬件自动完成的,硬件只负责将返回地址保存到相应的链接寄存器r14中去)由编译器插入的代码完成压栈工作)。当程序执行流程需要返回的时候,通过调用相应的返回指令(ARM处理器没有专门的返回指令,只能通过其他指令完成)将堆栈中保存的返回地址弹出到PC中

利用堆栈保存在被调函数中需要使用的寄存器值

当程序的控制权进入到被调函数(Callee)后,被调函数的代码函数的代码可能需要用到一些寄存器作为数据暂存,但是这些寄存器可能已经被(Caller)函数(调用函数)使用,为了满足Callee的需求,而不至于损坏Caller中已经使用的数据,编译器会在callee函数开始使用这些寄存器之前,将这些寄存器中的原有数据压入到堆栈保存,在Callee返回Caller之前,编译器还需要插入一段代码将这些保存在堆栈中的数据恢复(通过退栈操作)到相关的寄存器中去;
高级C语言教程-存储器和指针_第1张图片
高级C语言教程-存储器和指针_第2张图片


在实际的C程序中,编译器会根据需要插入维护这些功能的代码,因此在函数调用的时候,编译器会维护一个与调用相关的栈结构,通常我们将这个栈结构称为调用栈帧(Call Stack Frame);
函数的返回值通常保存在r0中。

正如大多数管理资源分配的算法一样,我们将在系统堆栈中构建空闲链表,每次的分配其实就是遍历整个空闲链表的各个空闲区域,如果某个空闲区域的大小能够满足用户申请的大小,系统将在高地址切一块分出来,,动态内存的释放就是动态申请的逆过程,释放函数首先将遍历整个空闲链表,寻找合适的位置将用户释放的内存块释放到空闲链表中去。

贵有恒,何必三更眠五更起;最无益,只怕一日曝十日寒!

你可能感兴趣的:(C-C++)