首页 > 其他 > 详细

《深入理解计算机系统》读书笔记(ch2)+ C 泛型

时间:2018-10-27 01:10:27      阅读:218      评论:0      收藏:0      [点我收藏+]

本章主要介绍各类型的机器表示,Stanford的CS107的lec2和lec3有精彩解释,比看书快(当作书中只是的cache吧)。

lec4中介绍的C里面如何使用泛型(没有template, reference)的技巧在此记录一下:

/*普通的swap函数*/
void
swap(int *ap, int *bp) { int temp = *ap; *ap = *bp;*bp = temp; } int x = 7; int y = 117; swap(&x, &y);//x=117, y=7

/*泛型swap函数, 错误实现*/
void swap(void *vp1, void *vp2)
{
void temp = *vp1; //不能dereference void指针,因为不知道指针类型,也就是不知道何时停止
*vp1 = *vp2;
*vp2 = temp;
}


/*泛型swap函数,正确实现*/
void swap(void *vp1, void *vp2, int size)//关键是交换bit pattern
{
char buffer(size);//需要编译器支持入参定义数组大小,char类型不重要,只是复制bit pattern。编译器不支持换用malloc即可
memcpy(buffer,vp1,size);
memcpy(vp1,vp2,size);
memcpy(vp2,buffer,size);
}
//对普通变量使用swap
int x=7,y=117;
swap(&x,&y,sizeof(int));
//对指针变量使用swap
char *husband = strdup("Fred");
char *wife = strdup("Wilma");
swap(&husband, &wife, sizeof(char *));

对比template实现的优势:不会导致代码膨胀(不同类型的template会在二进制中复制自己的版本)。

劣势:内存管理复杂。

先介绍一下泛型实现的linear search:

//linear search for int array
int lsearch(int key, int array[], int size)
{
    for (int i=0 ;i<size; i++)
    {
        if( array[i] == key){
            return i;    
        }
    }
}        


//generic linear search,只对基本类型有效,struct等可包含指针的类型无效
void  *lsearch( void *key, void *base, int n, int elemSize)
{
    for(int i=0; i<n; i++)
    {
        void *elemAddr = (char *)base + i*elemSize;//void star hack,将指针算数等价为普通算数运算,因为char的大小为1
        if(memcmp(key,elemAddr,elelSize)==0){
            return elemAddr;
        }
    }
}



//generic linear search
void *lsearch(void *key, void *base, int n, int elemSize, int (*cmpFn)(void*,void*))
{
    for(int i=0; i<n; i++)
{

     void *elemAddr = (char *)base + i*elemSize;//void star hack,将指针算数等价为普通算数运算,因为char的大小为1
        if(cmpFn(key, elemAddr) == 0){//hook
return elemAddr;
}
}  
return NULL; }

//use lsearch for int
int array[] = {4,2,3,7,11,6};
int size = 6;
int number = 7;

int IntCmp(void *elem1, void *elem2)
{
int *ip1 = elem1;
int *ip2 = elem2;
return *ip1-*ip2;
}

int *found = lsearch(&number,array,6,sizeof(int),IntCmp);
if(found==NULL)printf("not found");

//use lsearch for char*
char *notes[] = {"Ab","F#","B","Gb","D"};
char *favoriteNote = "Eb";

int StrCmp(void *elem1, void *elem2)
{
char *s1 = *(char **)elem1;// 先说明指针类型,然后解引用,得到一个char *
char *s2 = *(char **)elem2;
return strcmp(s1,s2);
}

char **found = lsearch(&favoriteNote, notes, 5, sizeof(char *), StrCmp);

//实际上lsearch和bsearch都是内建泛型函数,bsearch接口如下
void *bsearch(void *key, void *base, int n, int elemSize, int (*cmp)(void *, void *));

 C中同样没有类的概念,结构体中的变量只能是public,要实现一个类似Stack的数据结构需要程序员自己注意用法(不要直接使用struc中的数据成员,而是使用配套的“方法”)

typedef struct{
    int *elems;
    int logicalLen;
    int allocLen;
}Stack;//12 bytes

void StackNew(Stack *s){
    s->logicalLen = 0;
s->allocLen = 4;
s->elems = malloc(4*sizeof(int));
assert(s->elems != NULL); }
void StackDispose(Stack *s){
free(s->elems);//be careful, s->elems shouldn‘t be null
}
void StackPush(Stack *s, int value){
if(s->logicalLen == s->allocLen){//空间不足时分配双倍空间
s->allocLen *=2;
s->elems = realloc(s->elems,s->allocLen*sizeof(int));//记得捕捉返回值,若地址变动可能指向死内存
//fun fact: C++ doesn‘t have its own realloc
assert(s->elems!=NULL);
}
s->elems[s->logicalLen] = value;
s->logicalLen++;
}
void StackPop(Stack *s){
assert(s->logicalLen>0);
s->logicalLen--;
return s->elems[s->logicalLen];
}
//使用Stack Stack s;//分配内存 StackNew(&s); for(int i = 0; i<5; i++){ StackPush(&s, i); } StackDispose(&s);

 下面介绍泛型实现的stack

typedef struct{
    void* elems;
    int logicalLen;
    int allocLen;
    int elemSize;

}Stack;


void StackNew(Stack *s, int elemSize){
    assert(s->elemSize>0);
    s->elemSize = elemSize;
    s->logicalLen = 0;
    s->allocLen = 4;
    s->elems = malloc(4*elemSize);
    assert(s->elems != NULL);
}

void StackDispose(Stack *s){
    free(s->elems);
}

static void StackGrow(Stack *s){//static声明的函数只能在本文件中被使用
    s->allocLen *=2;
    s->elems = realloc(s->elems, s->allocLen*s->elemSize );
}

void StackPush(Stack *s, void *elemAddr){
    if(s->logicalLen == s->allocLen) StackGrow(s);

    void *target = (char*)elems + s->logicalLen*s->elemSize;

    memcpy(target,elemAddr,s->elemSize);
    s->logicalLen++;
    
}

void StackPop(Stack *s, void *elemAddr){
    void *source = (char*)s->elems + (s->logicalLen-1)*s->elemSize;
    memcpy(elemAddr, source, s->elemSize);
    s->logicalLen--;
}

 

《深入理解计算机系统》读书笔记(ch2)+ C 泛型

原文:https://www.cnblogs.com/42-Curry/p/9824727.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!