原创 简洁之一:避免臭虫(BUG)

2011-11-1 18:16 2469 14 24 分类: 消费电子

       对于每个程序员来说,不犯错误的可能性是没有的,但是通过不断的经验积累,就能有意识主动避免了很多错误,慢慢的错误也就少了,错误一般分为三种:


1.编译出错


       这种错误是编译时,编译器报告出来的,刚进入编程是最容易犯。这只是语法错误,等到有了一些经验之后,还是会犯这样的错误,不过会少得多,而且你能更快地发现错误原因。等到经验更丰富之后你就会觉得,语法错误是最简单最低级的错误,编译器的错误提示也就那么几种,即使错误提示是有误导的也能够立刻找出真正的错误原因是什么。相比下面两种错误,语法错误解决起来要容易得多。


2.运行出错


        编译器检查不出这类错误,仍然可以生成可执行文件,但在运行时会出错而导致程序崩溃。一般这种错误容易重现,有丰富调试经验的人也容易找出问题所在。所以真正的程序员必须具有丰富的软件调试经验。


3.逻辑出错


       这类错误是比较难发现的,编译和运行都会很顺利,看上去也不产生任何错误信息,但是程序没有干它该干的事情,而是干了别的事情。特别是一些边界或者临界错误,他们不会随便发生,想要重现来寻找问题是有一定难度的,为了找这种问题,有时不得不审视一行行源码漏洞可能。


       要避免臭虫,这自然就和之初软件设计有莫大的关系,一个简单软件功能,也可以有千奇百怪的不同实现方式,但一种比较简洁的方式去实现,就能避免很多的臭虫。简洁并不是简单。


例如有一个双向链表
typedef struct node *link;
struct node {    // 链表成员结构体
        link prev, next;
        unsigned char item;
};
link head = NULL;    // 链表头
void insert(link p)    // 添加成员
{
        p->next = head;
        if (head)
                head->prev = p;
        head = p;
        p->prev = NULL;
}
link delete(link p)    // 删除成员
{
        if (p->prev)
                p->prev->next = p->next;
        else
                head = p->next;
        if (p->next)
                p->next->prev = p->prev;
        return p;
}
现加入一个新的功能,要求每个链表成员具有10分钟生存期,每分钟将调用checkOverTime函数将表中超过时间成员剔除。
初眼看到这个问题,可能很多程序员觉得很EASY,没多想就开始直接编写代码。有兴趣的可以自行先做,在看看下面本人的实现,比较一下有何差别。
.
.
.
.
.
.
.
.
.
.
.
.
首先思考,链表成员现在具有时间属性,故成员结构体需要增加一个时间属性。
struct node {    // 链表成员结构体
        link prev, next;
        unsigned char item;
        unsigned long time;
};
但如何来使用这个变量呢?
也许有人就开始这么简单折腾了,在insert函数加入p->time = 10;编写下面函数
void checkOverTime(void)
{
    link p = head;
    while(p != NULL) {
        p->time--;
        if(p->time == 0) {
            delete(p);
        }
        p = p->next;
    }
}
这么做确实很简单,也很好,看不出有任何错误问题。但是否这就是最好的做法呢?
其实再深入思考一下,这么遍历整个列表,如果列表成员数少,确实是一种不错做法,但是成员很多的情况下,checkOverTime函数每秒检查调用,是否可取就得很好斟酌了,它也许就成为一条臭虫。
        我们仔细考虑到成员的加入,这不就是按照时间先后顺序进行插入吗?如果将time变量用来记录当前加入的时间,其实就只需检查最早插入成员是否超时,一旦没有超时,后面也就没有必要进行检查了。但是time记录什么,又会是一个很考究的问题,如果当前是linux系统,清楚jiffies值的含义,记录当时jiffies值将是一个最佳的选择。对双向链表作了些修改补充,那么最后的源码:
typedef struct node *link;
struct node {    // 链表成员结构体
        link prev, next;
        unsigned char item;
        unsigned long time;
        //...
};
typedef struct {
    link head, tail;
} tag_list;
tag_list list = {NULL,NULL};    // 链表
void insert(link p)    // 添加成员
{
        p->recv = list.tail;
        p->next = NULL;
        if (list.tail == NULL) {
                list.head = p;
                list.tail = p;
        } else {
                list.tail->next = p;
                list.tail = p;
        }
        p->time = jiffies;
}
link delete(link p)    // 删除成员
{
        if (p->prev == NULL) {
                list.head = p->next;
                list.head->prev = NULL;
        } else {
                p->prev->next = p->next;
        }
        if (p->next == NULL) {
               list.tail = p->prev;
               list.tail->next = NULL;
        } else {
                p->next->prev = p->prev;
        }
        return p;
}

void checkOverTime(void)
{
    link p;

    p = list.head;
    while(p != NULL) {
        if(jiffies - p->time > (10 * 60 * HZ)) {
            delete(p);
            free(p);
        } else break;
        p = p->next;
    }
}
上面只是范例,实际应用还需要考虑很多其它因素,且只能在单线程上调用操作,多线程间使用还需要作重入保护问题的考虑。

 

文章评论10条评论)

登录后参与讨论

xucun915_925777961 2011-11-7 14:36

来学习一下^_^

用户1185343 2011-11-7 11:50

不否认可以把案例看成是一个优化问题,只想表达一个想法,链表的操作设计,预先想到要避免链表大小影响,说明对链表应用已有一个很好的本质认识,设计的出发点就比较高,自然会主动避免设计缺陷问题。这自然要求林冲替身说的扎实的基本功,没能深入看到问题,是谈不上去优化的,不一定是没责任心和不追求质量。

用户1515844 2011-11-6 14:58

好!

用户1335696 2011-11-4 20:01

good

用户1147991 2011-11-4 16:20

同意

用户1185343 2011-11-4 13:01

对臭虫(BUG)的定义,可能我们之间看法不同。如同千年虫问题,快到2000年人们才意识到这条臭虫。简洁:简单明了,不留死角(没有绝对,尽量吧!)。

用户1625031 2011-11-3 18:10

受教了

用户1629079 2011-11-3 10:40

楼主,例子中表现的倾向于一个优化问题,而不是BUG。 与你希望表达的简洁也有距离。 BUG的减少,个人总结是责任心、代码质量的追求、扎实的基本功。

用户1602177 2011-11-1 18:13

简洁并不是简单!学习~~

用户1185343 2011-11-1 18:05

希望大家来讨论,避免臭虫是我们需要面对,只有我预先做足这方面,那么我们的软件将会是优秀的软件。
相关推荐阅读
用户1185343 2011-11-17 10:30
评论:@武晔卿 博客中提到的“改进我们日常管理的工作方法”
工作方法方式是很重要,你想“事半功倍”吗?...
用户1185343 2011-11-17 10:00
评论:@武晔卿 博客中提到的“MISRA:2004 嵌入式软件可靠性设计规范(1)”
没有规矩不成方圆...
用户1185343 2011-11-17 09:59
评论:@武晔卿 博客中提到的“电子设备的可使用性设计规范(1)”
没有规矩不成方圆...
用户1185343 2011-10-13 15:35
学会简洁
简洁不代表简单,其实是繁杂的本质提升。 要做到简洁设计,就需要我们透过表象得到本质要求。 我们需要经验、我们需要知识、我们需要分析方法。 希望我们来共同努力提高。...
我要评论
10
14
关闭 站长推荐上一条 /2 下一条