第二章 写的又好又快的秘诀¶
2.3 避免常见错误¶
strcpy , strcat, sprintf, 与 strncpy , strncat, snprintf,
sizeoff
valotile
intptr_t, uintptr_t
这两个数据类型的定义,位于 /usr/include/stdint.h 文件中,这个文件是在 C99 中新增加的文件, /usr/include/inttypes.h C99 新增加的文件,在这个文件中有 #include<stdint.h> ,
因此,使用时,既可以
#include <stdint.h>
又可以
#include <inttypes.h>
在 /usr/include/stdint.h 中定义:
/* Types for `void *' pointers. */ #if __WORDSIZE == 64 # ifndef __intptr_t_defined typedef long int intptr_t; # define __intptr_t_defined # endif typedef unsigned long int uintptr_t; #else # ifndef __intptr_t_defined typedef int intptr_t; # define __intptr_t_defined # endif typedef unsigned int uintptr_t; #endif
- 提高程序的可移植性(在32位和64位的机器上).
- 定义这两个数据类型别名也是为了 void * 指针. 在C语言中,任何类型的指针都可以转换为 void * 类型,并且在将它转换回原来的类型时不会丢失信息。
2.4 自动测试¶
/*
* File: dlist.h
*/
#include <stdio.h>
#ifndef DLIST_H
#define DLIST_H
#ifdef __cplusplus
extern "C" {
#endif/*__cplusplus*/
typedef enum _DListRet
{
DLIST_RET_OK,
DLIST_RET_OOM,
DLIST_RET_STOP,
DLIST_RET_INVALID_PARAMS,
DLIST_RET_FAIL
}DListRet;
struct _DList;
typedef struct _DList DList;
typedef void (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int (*DListDataCompareFunc)(void* ctx, void* data);
typedef DListRet (*DListDataVisitFunc)(void* ctx, void* data);
DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx);
DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t dlist_length(DList* thiz);
int dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);
void dlist_destroy(DList* thiz);
#define return_if_fail(p) if(!(p)) \
{printf("%s:%d Warning: "#p" failed.\n", \
__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
{printf("%s:%d Warning: "#p" failed.\n",\
__func__, __LINE__); return (ret);}
#ifdef __cplusplus
}
#endif/*__cplusplus*/
#endif/*DLIST*/
/*
* File: dlist.c
*/
#include <stdlib.h>
#include <stdint.h>
#include "dlist.h"
typedef struct _DListNode
{
struct _DListNode* prev;
struct _DListNode* next;
void* data;
}DListNode;
struct _DList
{
DListNode* first;
void* data_destroy_ctx;
DListDataDestroyFunc data_destroy;
};
static void dlist_destroy_data(DList* thiz, void* data)
{
if(thiz->data_destroy != NULL){
thiz->data_destroy(thiz->data_destroy_ctx, data);
}
return;
}
static DListNode* dlist_create_node(DList* thiz, void* data)
{
DListNode* node = malloc(sizeof(DListNode));
if(node != NULL){
node->prev = NULL;
node->next = NULL;
node->data = data;
}
return node;
}
static void dlist_destroy_node(DList* thiz, DListNode* node)
{
if(node != NULL){
node->next = NULL;
node->prev = NULL;
dlist_destroy_data(thiz, node->data);
free(node);
}
return;
}
DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx)
{
DList* thiz = malloc(sizeof(DList));
if(thiz != NULL){
thiz->first = NULL;
thiz->data_destroy = data_destroy;
thiz->data_destroy_ctx = data_destroy_ctx;
}
return thiz;
}
static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
DListNode* iter = NULL;
return_val_if_fail(thiz != NULL, NULL);
iter = thiz->first;
while(iter != NULL && iter->next != NULL && index > 0){
iter = iter->next;
index--;
}
if(!fail_return_last){
iter = index > 0 ? NULL : iter;
}
return iter;
}
DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
DListNode* node = NULL;
DListNode* cursor = NULL;
return_val_if_fail(thiz != NULL, DLIST_RET_INVALID_PARAMS);
if((node = dlist_create_node(thiz, data)) == NULL){
return DLIST_RET_OOM;
}
if(thiz->first == NULL){
thiz->first = node;
return DLIST_RET_OK;
}
cursor = dlist_get_node(thiz, index, 1);
if(index < dlist_length(thiz)){
if(thiz->first == cursor){
thiz->first = node;
}else{
cursor->prev->next = node;
node->prev = cursor->prev;
}
node->next = cursor;
cursor->prev = node;
}else{
cursor->next = node;
node->prev = cursor;
}
return DLIST_RET_OK;
}
DListRet dlist_prepend(DList* thiz, void* data)
{
return dlist_insert(thiz, 0, data);
}
DListRet dlist_append(DList* thiz, void* data)
{
return dlist_insert(thiz, -1, data);
}
DListRet dlist_delete(DList* thiz, size_t index)
{
DListNode* cursor = dlist_get_node(thiz, index, 0);
return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS);
if(cursor != NULL)
{
if(cursor == thiz->first){
thiz->first = cursor->next;
}
if(cursor->next != NULL){
cursor->next->prev = cursor->prev;
}
if(cursor->prev != NULL){
cursor->prev->next = cursor->next;
}
dlist_destroy_node(thiz, cursor);
}
return DLIST_RET_OK;
}
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
DListNode* cursor = dlist_get_node(thiz, index, 0);
return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS);
if(cursor != NULL){
*data = cursor->data;
}
return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
DListNode* cursor = dlist_get_node(thiz, index, 0);
return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS);
if(cursor != NULL){
cursor->data = data;
}
return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}
size_t dlist_length(DList* thiz)
{
size_t length = 0;
DListNode* iter = NULL;
return_val_if_fail(thiz != NULL, 0);
iter = thiz->first;
while(iter != NULL){
length++;
iter = iter->next;
}
return length;
}
DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
DListRet ret = DLIST_RET_OK;
DListNode* iter = NULL;
return_val_if_fail(thiz != NULL && visit != NULL, DLIST_RET_INVALID_PARAMS);
iter = thiz->first;
while(iter != NULL && ret != DLIST_RET_STOP){
ret = visit(ctx, iter->data);
iter = iter->next;
}
return ret;
}
int dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
int i = 0;
DListNode* iter = NULL;
return_val_if_fail(thiz != NULL && cmp != NULL, -1);
iter = thiz->first;
while(iter != NULL){
if(cmp(ctx, iter->data) == 0){
break;
}
i++;
iter = iter->next;
}
return i;
}
void dlist_destroy(DList* thiz)
{
DListNode* iter = NULL;
DListNode* next = NULL;
return_if_fail(thiz != NULL);
iter = thiz->first;
while(iter != NULL){
next = iter->next;
dlist_destroy_node(thiz, iter);
iter = next;
}
thiz->first = NULL;
free(thiz);
return;
}
#ifdef DLIST_TEST
#include <assert.h>
static int cmp_int(void* ctx, void* data)
{
//return (int)data - (int)ctx;
return (intptr_t)data - (intptr_t)ctx;
}
static DListRet print_int(void* ctx, void* data)
{
//printf("%d ", (int)data);
//printf("%d ", (intptr_t)data);
printf("%p ", data);
//printf("%ld ", (intptr_t)data);
return DLIST_RET_OK;
}
static DListRet check_and_dec_int(void* ctx, void* data)
{
//int* expected =(int*)ctx;
//assert(*expected == (int)data);
intptr_t* expected =(intptr_t*)ctx;
assert(*expected == (intptr_t)data);
(*expected)--;
return DLIST_RET_OK;
}
void test_int_dlist(void)
{
//int s = 0;
//int i = 0;
//int n = 100;
//int data = 0;
intptr_t s = 0;
intptr_t i = 0;
intptr_t n = 100;
intptr_t data = 0;
DList* dlist = dlist_create(NULL, NULL);
for(i = 0; i < n; i++){
assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
assert(dlist_length(dlist) == (i + 1));
assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
assert(data == i);
assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == DLIST_RET_OK);
assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
assert(data == 2*i);
assert(dlist_set_by_index(dlist, i, (void*)i) == DLIST_RET_OK);
assert(dlist_find(dlist, cmp_int, (void*)i) == i);
}
for(i = 0; i < n; i++){
assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
assert(data == (i));
assert(dlist_length(dlist) == (n-i));
assert(dlist_delete(dlist, 0) == DLIST_RET_OK);
assert(dlist_length(dlist) == (n-i-1));
if((i + 1) < n){
assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
assert((int)data == (i+1));
}
}
assert(dlist_length(dlist) == 0);
for(i = 0; i < n; i++){
assert(dlist_prepend(dlist, (void*)i) == DLIST_RET_OK);
assert(dlist_length(dlist) == (i + 1));
assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
assert(data == i);
assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == DLIST_RET_OK);
assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
assert(data == 2*i);
assert(dlist_set_by_index(dlist, 0, (void*)i) == DLIST_RET_OK);
}
i = n - 1;
assert(dlist_foreach(dlist, check_and_dec_int, &i) == DLIST_RET_OK);
s = dlist_length(dlist);
for(i = 1; i < n; i++){
assert(dlist_insert(dlist, i, (void*)i) == DLIST_RET_OK);
assert(dlist_length(dlist) == (s + i));
assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
assert(data == i);
assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == DLIST_RET_OK);
assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
assert(data == 2*i);
assert(dlist_set_by_index(dlist, i, (void*)i) == DLIST_RET_OK);
}
dlist_destroy(dlist);
return;
}
void test_invalid_params(void)
{
printf("===========Warning is normal begin==============\n");
assert(dlist_length(NULL) == 0);
assert(dlist_prepend(NULL, 0) == DLIST_RET_INVALID_PARAMS);
assert(dlist_append(NULL, 0) == DLIST_RET_INVALID_PARAMS);
assert(dlist_delete(NULL, 0) == DLIST_RET_INVALID_PARAMS);
assert(dlist_insert(NULL, 0, 0) == DLIST_RET_INVALID_PARAMS);
assert(dlist_set_by_index(NULL, 0, 0) == DLIST_RET_INVALID_PARAMS);
assert(dlist_get_by_index(NULL, 0, NULL) == DLIST_RET_INVALID_PARAMS);
assert(dlist_find(NULL, NULL, NULL) < 0);
assert(dlist_foreach(NULL, NULL, NULL) == DLIST_RET_INVALID_PARAMS);
printf("===========Warning is normal end==============\n");
return;
}
int main(int argc, char* argv[])
{
test_int_dlist();
test_invalid_params();
return 0;
}
#endif
ARCH=-m32
all:
gcc -g ${ARCH} -fPIC -shared dlist.c -o libdlist.so
gcc -g ${ARCH} -DDLIST_TEST dlist.c -o dlist_test
clean:
rm -f *test *.exe *.so