c语言的实践技巧

看了《两则c语言技巧》文章之后,很高兴又学会了两招用法!但是技巧毕竟还是要与实际应用相结合的,所以我下面就谈一下我自己对这些技巧的看法,并贡献自己发现的一下c

语言的用法。
1. Enum
    {
        FRUIT_APPLE,
        FRUIT_PEAR,
        FRUIT_BANANA,
        FRUIT_NR
    };

    int price[FRUIT_NR] = { [FRUIT_APPLE] = 20, [FRUIT_PEAR] = 25, [FRUIT_BANANA] = 30};
上面这种用法较常规用法的好处是不用来回移动数组内容,也更具有可读性和修改性!一般我会将这种用法用在配置数据上,比如我们需要为一个下列框填值,但是显示的值序列

还不确定,这种方式就很好的适应这种需求。如果扩展这种使用方式,可以用来模拟一个配置文件的用途,这在嵌入式开发中是很有益的。

2. case的连用,虽然这种方式比较简便但是牺牲了可修改性,除非非常确定不准备扩展中间case的处理,所以不建议使用。

c语言中还有其他的使用技巧,我最近发现一个,使用结构体来封装一个类似于c++中类的对象,使用结构体和函数指针相结合。
具体的使用看下面给出一个实现的循环队列的实现。
在"cqueue.h"中如下定义

struct  tagAlgCycQueue;
typedef struct tagAlgCycQueue ALG_CYC_QUEUE;
typedef struct tagAlgCycQueue* PALG_CYC_QUEUE;

typedef  int (* CQ_IsFull) (PALG_CYC_QUEUE);
typedef  int (* CQ_IsEmpty) (PALG_CYC_QUEUE);
typedef  void (* CQ_InQueue) (PALG_CYC_QUEUE, void *);
typedef  void* (* CQ_OutQueue) (PALG_CYC_QUEUE);
typedef  int (* CQ_Reverse) (PALG_CYC_QUEUE);
typedef  void (* CQ_Jump)(PALG_CYC_QUEUE, int);


struct tagAlgCycQueue
{
    int nStartPos;
    int nCurPos;
    int nEndPos;
    int bInited;
    int nElementSize;
    int bDirect;
    int nLength;

    void* pBuf;

    /*
     * 注意这里:用到前面的函数定义,通过这几个函数定义,我们就可以实现自己的算法,
     * 如果别人不满意也可以从这里修改来添加他自己的算法实现。
     */
    CQ_IsFull  IsFull;
    CQ_IsEmpty IsEmpty;
    CQ_InQueue InQueue;
    CQ_OutQueue OutQueue;
    CQ_Reverse  Reverse;
    CQ_Jump     Jump;
};

这个函数用于初始化一个队列结构
extern ALG_InitCycQueue(PALG_CYC_QUEUE pQueue,
                        int len, void *pBuf, int em_size);

在"cqueue.c"文件中实现
#define _TEST_QUEUE(b) { \
                           if ( !(b) ) \
                           { \
                               printf("error: queue don't initialize!\n"); \
                               return -1; \
                           } \
                       }

 


static int ALG_CQ_IsFull(PALG_CYC_QUEUE pQueue)
{
    _TEST_QUEUE(pQueue->bInited);
    return ( ((pQueue->nEndPos + 1) % pQueue->nLength) == pQueue->nStartPos );   
}

static int ALG_CQ_IsEmpty(PALG_CYC_QUEUE pQueue)
{
    _TEST_QUEUE(pQueue->bInited);
    return ( ((pQueue->nStartPos + 1) % pQueue->nLength) == pQueue->nEndPos );
}

static int ALG_CQ_InQueue(PALG_CYC_QUEUE pQueue, void *pEm)
{
    _TEST_QUEUE(pQueue->bInited);
    if ( ALG_CQ_IsFull(pQueue) )
        return 0;

    if ( NULL == pEm )
    {
        memset(pQueue->pBuf+pQueue->nElementSize*pQueue->nEndPos, 0, pQueue->nElementSize);
    }
    else
    {
        memcpy(pQueue->pBuf+pQueue->nElementSize*pQueue->nEndPos, pEm, pQueue->nElementSize);
    }
    pQueue->nEndPos = (++pQueue->nEndPos) % pQueue->nLength;
    return 1;
}

static void* ALG_CQ_OutQueue(PALG_CYC_QUEUE pQueue)
{
    _TEST_QUEUE(pQueue->bInited);
    if ( ALG_CQ_IsEmpty(pQueue) )
        return NULL;
   
    pQueue->nStartPos = (++pQueue->nStartPos) % pQueue->nLength;
    return (pQueue->pBuf + pQueue->nElementSize*pQueue->nStartPos);
}

static void ALG_CQ_Jump(PALG_CYC_QUEUE pQueue, int offset)
{
    int i = offset;
   
    _TEST_QUEUE(pQueue->bInited);
    while ( i > 0 )
    {
        if ( ALG_CQ_IsFull(pQueue) )
        {
            ALG_CQ_OutQueue(pQueue);
        }
        ALG_CQ_InQueue(pQueue, NULL);
        i--;
    }  
}


/*
 * DESC: this function is used to initialize tagAlgDCycQueue struct, you must call
 *      this function when you want to use tagAlgDCycQueue object.
 *
 * IN  :pQueue      tagAlgDCycQueue point
 *      len         queue length
 *      pBuf        queue buffer
 *      em_size     the element size in queue
 *
 * RET : if success return 1, else return 0
 */
int ALG_InitCycQueue(PALG_CYC_QUEUE pQueue,
                                 int len, void* pBuf, int em_size)
{
    if ( NULL == pQueue || NULL == pBuf )
        return 0;

    pQueue->nLength = len;
    pQueue->nElementSize = em_size;
    pQueue->pBuf = pBuf;
    pQueue->nStartPos = 0;
    pQueue->nEndPos   = pQueue->nStartPos + 1;
    pQueue->nCurPos   = 0;
    pQueue->bInited   = 1;
    pQueue->bDirect   = 0;

    pQueue->IsEmpty   = ALG_CQ_IsEmpty;
    pQueue->IsFull    = ALG_CQ_IsFull;
    pQueue->InQueue   = ALG_CQ_InQueue;
    pQueue->OutQueue  = ALG_CQ_OutQueue;
    pQueue->Jump      = ALG_CQ_Jump;

    return pQueue->bInited;
};
这样就可以实现一个比较原始的循环队列的操作了,并且我们也对这个操作进行了一定的封装。
但是以上的封装还是有些问题,就是结构体内部的变量没进行保护,呵呵,这个目前还没有找到解决
方法。

posted @ 2006-12-24 00:51  moonz-wu  阅读(395)  评论(0编辑  收藏  举报