主题 : 嵌入式C语学习笔记几个重要关键字.doc 复制链接 | 浏览器收藏 | 打印
刚刚成立的新群linux+arm+dsp+pcb+fuck交流群,欢迎各位fuck友加入。 群号211670713 &nbs ..
级别: 新手上路
UID: 77327
精华: 0
发帖: 11
金钱: 55 两
威望: 11 点
贡献值: 0 点
综合积分: 22 分
注册时间: 2012-09-06
最后登录: 2013-03-15
楼主  发表于: 2013-03-07 20:44

 嵌入式C语学习笔记几个重要关键字.doc

一、static
关键字static,修饰变量时:
1、限制该变量的作用域:比如静态全局变量,只能在该模块中使用(本c文件中)。
2、决定该变量的存储位置:修饰为静态的变量,存储在静态数据区(非堆栈内)。(同比,全局变量也都存放在静态数据区中。)
带初值和不带初值的静态变量:(以TI DSP 54XX为例)
a.不带初值的静态变量,存储在.bss段中。
b.带初值的静态变量,存储在.bss段中,但其初值存储在.init中。在DSP Booter完成加载初始化后已经将init段的值赋值到.bss对应变量中。
关键字static,修饰函数时:限制该函数的作用域,仅能在本模块中使用(本c文件中)。
结论:static关键字对于使用者而言,最重要的是对变量或函数作用域的限制。
二、const
关键字const意味着“不变的”:
1、什么时候该用:定义一个函数时如果在输入参数前加上const,可以防止该输入变量被改写而引出的错误;函数定义时使用const可以起到函数API自注释作用;
2、怎么用:
以下摘录经典面试题中的例子:
const int a; int const a; const int *a; int * const a; int const * a const;
前两个的作用是一样,a是一个常整型数。
第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。
第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
三、volatile
关键字volatile意味着“易改变的”:
修饰为volatile的变量,编译器不会对其进行任何优化,每次求值时会到指定地址(物理或映射)去读取。因此适用于“并行设备的硬件寄存器(如:状态寄存器) ;一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) ;多线程应用中被几个任务共享的变量 ”,我个人只用到在IO和中断中。
四、堆与栈(heap and stack)
1) 堆是由用户维护的。比如我们malloc一段空间,此时开辟的空间便在堆中,调用free时再释放。过于频繁的malloc与free会导致堆中产生碎片(一个空间的地址不连续),影响读写速度。
2) 栈是由编译器控制的,我们无需干涉。比如我们定义的局部变量或是调用了一个函数。以函数调用为例,此时系统会将现场数据(主要是部分寄存器中的数据,如PC的保存可以在调用结束时程序回归此处继续运行)压入栈内,将寄存器空出迎接被调函数中的一系列计算和控制。被调函数执行完后再进行出栈操作,流程继续。
栈与队列的区别:

栈——先入后出,后入先出;

队列——先入先出,后入后出;

应用举例:

栈:函数调用时会将临时数据压栈;函数返回时再弹出来。

队列:一般,系统中的任务和消息经常使用队列。可以按任务或消息到来的先后顺序执行。

代码实现:

背景:使用C语言,在VS2008环境下,按栈与队列的原理,采用最简单易懂的方式,针对正整型(int)元素实现栈与队列。

原理:栈的存储空间使用数组构造,队列的空间又使用栈来构造,即,使用两个栈实现队列的功能。

文件:libStack.h/c;libQueue.h/c;

一、栈的源代码

libStack.h

#ifndef _LIBSTACK_H  
#define _LIBSTACK_H  
  
#ifdef __cplusplus  
extern "C" {  
#endif  
  
#define STACK_MAX_LEN   2048  
  
typedef struct tagstStack  
{  
    int udwPc;              /* 栈顶所在位置,指向空闲位置 */  
    int a[STACK_MAX_LEN];  
}stStack;  
  
/* 创建新的栈 */  
extern stStack *stack_new();  
  
/* 栈复位 */  
extern void stack_reset(stStack *pstStack);  
  
/* 入栈,栈满时忽略此次操作 */  
extern void stack_push(stStack *pstStack,int udwTmp);  
  
/* 出栈,栈空时返回-1 */  
extern int stack_pop(stStack *pstStack);  
  
/* 栈判空 1-空 0-非空 */  
extern int stack_is_empty(stStack *pstStack);  
  
/* 删除栈 */  
extern void stack_delete(stStack *pstStack);  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif  
由于是C语言实现,所以必须添加extern "C"{};

libStack.c

#ifdef __cplusplus  
extern "C" {  
#endif  
  
#include <malloc.h>  
#include <stddef.h>  
#include "libStack.h"  
  
/* 创建新的栈 */  
stStack *stack_new()  
{  
    stStack *p;  
    p = (stStack *)malloc(sizeof(stStack));  
    p->udwPc = 0;  
    return p;  
}  
  
/* 栈复位 */  
void stack_reset(stStack *pstStack)  
{  
    if (NULL == pstStack)  
    {  
        return;  
    }  
    pstStack->udwPc = 0;  
}  
  
/* 入栈,栈满时忽略此次操作 */  
void stack_push(stStack *pstStack, int udwTmp)  
{  
    if (NULL == pstStack)  
    {  
        return;  
    }  
  
    if (STACK_MAX_LEN > pstStack->udwPc)  
    {  
        pstStack->a[pstStack->udwPc] = udwTmp;  
        pstStack->udwPc++;  
    }  
}  
  
/* 出栈,栈空时返回-1 */  
int stack_pop(stStack *pstStack)  
{  
    if (NULL == pstStack)  
    {  
        return -1;  
    }  
  
    if (0 == pstStack->udwPc)  
    {  
        return -1;  
    }  
    return pstStack->a[--pstStack->udwPc];  
}  
  
/* 栈判空 1-空 0-非空 */  
int stack_is_empty(stStack *pstStack)  
{  
    if (NULL == pstStack)  
    {  
        /* 空指针默认为空栈 */  
        return 1;  
    }  
  
    return (0 < pstStack->udwPc)?0:1;  
}  
  
/* 删除栈 */  
void stack_delete(stStack *pstStack)  
{  
    if (NULL != pstStack)  
    {  
        free(pstStack);  
    }  
}  
  
#ifdef __cplusplus  
}  
#endif  
本套实现只支持正整型数,负数被作为异常值处理。
二、队列的实现

这里队列完全是用上述栈实现的,目的只是练习。

libQueue.h

#ifndef _LIBQUEUE_H  
#define _LIBQUEUE_H  
  
#ifdef __cplusplus  
extern "C" {  
#endif  
  
#include "libStack.h"  
  
#define QUEUE_MAX_LEN STACK_MAX_LEN     /* 队列大小取决与栈的大小 */  
  
typedef struct tagstQueue  
{  
    int     udwCnt;  
    stStack *pstStack1;              
    stStack *pstStack2;  
}stQueue;  
  
/* 创建新队列 */  
extern stQueue *queue_new();  
  
/* 入队,队列已满时忽略此次操作 */  
extern void in_queue(stQueue *pstQueue, int udwTmp);  
  
/* 出队,队列为空时返回-1 */  
extern int out_queue(stQueue *pstQueue);  
  
/* 删除队列 */  
extern void queue_delete(stQueue *pstQueue);  
  
/* 队列判空 1-空 0-非空 */  
extern int queue_is_empty(stQueue *pstQueue);  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif  
libQueue.c
#ifdef __cplusplus  
extern "C" {  
#endif  
  
#include <malloc.h>  
#include <stddef.h>  
#include "libQueue.h"  
  
/* 创建新队列 */  
stQueue *queue_new()  
{  
    stQueue *p;  
    p = (stQueue *)malloc(sizeof(stQueue));  
    if (NULL == p)  
    {  
        return NULL;  
    }  
  
    p->pstStack1 = stack_new();  
    if (NULL == p->pstStack1)  
    {  
        free(p);  
        return NULL;  
    }  
  
    p->pstStack2 = stack_new();  
    if (NULL == p->pstStack2)  
    {  
        free(p);  
        free(p->pstStack1);  
        return NULL;  
    }  
  
    p->udwCnt = 0;  
  
    return p;  
}  
  
/* 入队,队列已满时忽略此次操作 */  
void in_queue(stQueue *pstQueue, int udwTmp)  
{  
    if (NULL == pstQueue)  
    {  
        return;  
    }  
  
    if (QUEUE_MAX_LEN <= pstQueue->udwCnt)  
    {  
        return;  
    }  
  
    stack_push(pstQueue->pstStack1, udwTmp);  
    pstQueue->udwCnt++;  
}  
  
/* 出队,队列为空时返回-1 */  
int out_queue(stQueue *pstQueue)  
{  
    int ret = -1;  
    int tmp = 0;  
  
    if (NULL == pstQueue)  
    {  
        return -1;  
    }  
  
    /* 队列为空 */  
    if (stack_is_empty(pstQueue->pstStack1))  
    {  
        return -1;  
    }  
  
    /* 将栈1内容弹出并压入栈2 */  
    while(0 != pstQueue->pstStack1->udwPc)  
    {  
        tmp = stack_pop(pstQueue->pstStack1);  
        stack_push(pstQueue->pstStack2, tmp);  
    }  
  
    /* 取栈2顶元素出队 */  
    ret = stack_pop(pstQueue->pstStack2);  
  
    /* 将栈2内容压回栈1 */  
    while(0 != pstQueue->pstStack2->udwPc)  
    {  
        tmp = stack_pop(pstQueue->pstStack2);  
        stack_push(pstQueue->pstStack1, tmp);  
    }  
  
    pstQueue->udwCnt--;  
  
    return ret;  
}  
  
/* 删除队列 */  
void queue_delete(stQueue *pstQueue)  
{  
    if (NULL == pstQueue)  
    {  
        return;  
    }  
  
    if (NULL != pstQueue->pstStack2)  
    {  
        free(pstQueue->pstStack2);  
    }  
  
    if (NULL != pstQueue->pstStack1)  
    {  
        free(pstQueue->pstStack1);  
    }  
  
    free(pstQueue);  
}  
  
/* 队列判空 1-空 0-非空 */  
int queue_is_empty(stQueue *pstQueue)  
{  
    return (0 < pstQueue->udwCnt)?0:1;  
}  
  
#ifdef __cplusplus  
}  
#endif  
三、简单的测试函数

这里我只写了队列的测试:

// ListStackQueue.cpp : 定义控制台应用程序的入口点。  
//  
#include "stdafx.h"  
#include "libStack.h"  
#include "libQueue.h"  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    int i,tmp;  
  
    stQueue *pstQ1 = queue_new();  
    stQueue *pstQ2 = queue_new();  
  
    for (i = 0; i < 20; i++)  
    {  
        in_queue(pstQ1,i);  
    }  
  
    for (i = 0; i < 20; i++)  
    {  
        tmp = out_queue(pstQ1);  
        printf("%d ",tmp);  
    }  
  
    printf("OK");  
    getchar();  
    return 0;  
}  
输出为:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 OK;实现了队列的先入先出功能。
如果试着将栈的大小调整为5,输出为:0 1 2 3 4 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 OK。满足超出空间上限不压栈不入队,出栈出队时若栈队为空则返回-1。




C语言作为面向过程的语言,想写出灵活的结构与封装需要很高技巧。
但由于C语言的高效,几乎所有操作系统和面向对象语言的最底层实现都使用了C语言。即,使用C完成面向对象的封装。
这次通过整理与仿写Linux的双向链表让我体会到了一些C语言封装的核心技巧。
这个双向链表的巧妙之处在于1)利用宏将“函数”入参扩展出了“结构类型”; 2)利用纯地址偏移获取结构体指针;
下面是具体实现:链表的实现由于是宏定义,都在libList.h中。
测试程序testList.c与testList.h。
libList.h
#ifndef _LIBLIST_H  
#define _LIBLIST_H  
  
#ifdef __cplusplus  
extern "C" {  
#endif  
  
/* 链表头节点定义 */  
typedef struct tagstList_Head {  
    struct tagstList_Head *next, *prev;  
}stList_Head;  
  
/* 初始化双向链表 */  
#define list_init(head) do          \  
{                       \  
    (head)->next = (head)->prev = (head); \  
} while(0)  
  
/* 在指定元素(where)之后插入新元素(item) */  
#define list_add(item, towhere) do  \  
{                   \  
    (item)->next = (towhere)->next;   \  
    (item)->prev = (towhere);    \  
    (towhere)->next = (item);    \  
    (item)->next->prev = (item);  \  
} while(0)  
  
/* 在指定元素(where)之前插入新元素(item) */  
#define list_add_before(item, towhere)  \  
    list_add(item,(towhere)->prev)  
  
/* 删除某个元素 */  
#define list_remove(item) do            \  
{                       \  
    (item)->prev->next = (item)->next; \  
    (item)->next->prev = (item)->prev; \  
} while(0)  
  
/* 正向遍历链表中所有元素 */  
#define list_for_each_item(item, head)\  
    for ((item) = (head)->next; (item) != (head); (item) = (item)->next)  
  
/* 反向遍历链表中所有元素 */  
#define list_for_each_item_rev(item, head) \  
    for ((item) = (head)->prev; (item) != (head); (item) = (item)->prev)  
  
/* 根据本节点(item)获取节点所在结构体(type)的地址 */  
/* 节点item地址(member的地址) - 该链表元素member在结构体中的偏移 */  
#define list_entry(item, type, member) \  
    ((type *)((char *)item - (char *)(&((type *)0)->member)))  
  
/* 判断链表是否为空 */  
#define list_is_empty(head) \  
    ((head)->next == (head))  
  
/* 获取指定位置上一元素 */  
#define list_prev_item(item)\  
    ((head)->prev)  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif  
testList.h
#ifndef _TESTLIST_H  
#define _TESTLIST_H  
  
#ifdef __cplusplus  
extern "C" {  
#endif  
  
#include "libList.h"  
  
typedef struct tagInteger  
{  
    int idx;  
    stList_Head stListHead;  
}stInteger;  
  
extern void testlist();  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif  
这种双向链表的特点在于:在需要链表管理的结构中定义一个链表节点变量,然后所有的操作都是针对这个链表节点进行的。在需要获取该结构时使用list_entry即可。
testList.c
#ifdef __cplusplus  
extern "C" {  
#endif  
  
#include <malloc.h>  
#include <stddef.h>  
#include "stdafx.h"  
#include "testList.h"  
  
void testlist()  
{  
    int i = 0;  
    stList_Head     stListHead;  
    stList_Head     *pstListHead= NULL;  
  
    stInteger       *pstInteger = NULL;  
    stList_Head     *pstTmpList = NULL;  
  
    /* 链表初始化 */  
    pstListHead = &stListHead;  
    list_init(pstListHead);  
  
    /* 生成节点并挂入链表 */  
    for(i = 0; i < 32; i++)  
    {  
        pstInteger = (stInteger *)malloc(sizeof(stInteger));  
        if (NULL == pstInteger)  
        {  
            printf("pstInteger malloc fail!");  
            return;  
        }  
        pstInteger->idx = 100 - i;  
  
        /* 挂到头结点之前 */  
        list_add_before(&pstInteger->stListHead, pstListHead);  
  
        /* 挂到头结点之后 */  
        //list_add(&pstInteger->stListHead, pstListHead);  
    }  
      
    /* 正向遍历链表中每一个元素并输出 */  
    list_for_each_item(pstTmpList, pstListHead)  
    {  
        if(NULL != pstTmpList)  
        {  
            pstInteger = list_entry(pstTmpList, stInteger, stListHead);  
            printf("%d ",pstInteger->idx);  
        }  
    }  
      
    return;  
  
}  
  
#ifdef __cplusplus  
{  
#endif  






刚刚成立的新群linux+arm+dsp+pcb+fuck交流群,欢迎各位fuck友加入。 群号211670713    群号211670713