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