老翅寒暑

一个老鸟的自白
随笔 - 90, 文章 - 0, 评论 - 742, 引用 - 24
数据加载中……

2009年12月3日

Crest的OO核心实现

至此,我们已经有了一个比较好用的宏封装的代码风格,一个基础的类对象结构的模拟代码,但是始终没有接触到OO的核心实现。这次,我们终于要进入实质的内容了---实现对象的继承和接口的实现。

单对象的内存布局

我们在《Crest的语法---宏的魔术汇演》实现了一个简单对象,含有成员变量,成员函数,如下图所示。其中buffer指向字符缓冲区,虚函数Format表现为一个函数指针。

这种结构把数据和成员函数一起放到了实例对象中,但是这个结构一旦遇到大规模的对象使用场景的时候,就会浪费很多空间,因为对于相同对象而言,其成员函数都是完全一样的,没有必要每一个对象都保留一份成员函数副本。所以我们可以把这样的结构修改一下:

这样就简单了,一个CString类在内存中可以有很多个实例,但是都共享同一个CStringType对象,CStringType对象负责存放虚函数和纯虚函数的指针。这个所谓的CStringType在C++里边叫做VTable,在delphi中叫做VMT,其实所有的OO语言都存在这个东西。

比较仔细的同学可能就有些疑问了,看前一篇文章中的代码,Format是虚函数,OnFormat是纯虚函数,DoFormat则是实函数,按照道理,实函数应该不要出现在CStringType中的。是的,因为我们用C语言的struct来模拟class,本来struct就不支持public / protected / private等可见性定义,模拟出来的都只能是public的,这是限制之一。如果我们还要严格区分虚实函数的话,也会因为C语言的限制,导致虚实函数调用语法的不一致,反而引来很多麻烦,更何况java也不区分虚实函数,它所有的成员函数都是虚函数,都是可以重载的,所以就算借鉴java的特性吧。

对象的继承结构

单个对象我们已经完成了内存布局的设计,接下来我们要实现类的继承。

要实现继承结构面临的第一个需求就是基类和派生类的相互转换。在编程实践中我们已经知道,基类和派生类之间,派生类可以当作基类一样来使用,就像 CObject obj = new CString() 这样,反过来也可以这样CString str = (CString) obj实现强制转换。大多数单继承结构的类都用简单的方法实现都是保证CString的前半部分和基类CObject的内存结构完全相同。

如上图所示,如果一个指针指向CString结构,因为内存结构相同,也就等同于指向了一个CObject结构。

也存在另外一种基类和派生类的转换方式,就是COM的QueryInterface的方式,所有的类型转换都通过调用QueryInterface来获得,这样的基类、派生类甚至接口,甚至都可以用不同的对象来实现,不过代价很大,暂时不用。

针对一个CString类,我们现在需要CString和CStringType配合使用才能完成一个整个类的功能,基类CObject同样也需要CObject和CObjectType配合。因此基类和派生类同构的原则同样要适用于CStringType和CObjectType之间。这样,从图中我们可以看到,一旦CString把自己的toString实现的函数指针填入CStringType的toString位置,就可以实现所谓的"重载(override)"。

这里要注意的是,自此,我们之前谈的this指针就隐含划分为两个部分,一个是CString,一个是CStringType。

但是我们如果要调用基类的函数呢?C++的语法是CObject::Format(xxx),java语法是super.Format(xxx),C#的语法和java类似。这里的关键是要不要在CStringType中设置一个指向CObjectType的指针。从易用性看,java/C#的方法更简单,C++的方法则有信息重复的嫌疑,万一修改基类名称了,C++需要修改不止一个地方,而java/C#则只需修改一个地方。但是我们的Crest实现的时候,如果用C++方式实现,则就可以不需要再CStringType中放置一个指针,否则就需要。这个在单片机编程时候可能更在意一些。决定放置一个指针,结构就变成了下图的样子:

接口实现

一个基本的单继承结构已经设计完毕,接下来要准备实现接口(interface)。和基类相比,接口就简单得多,因为接口不涉及到数据,所以所有的工作就集中在我们如何来调整CStringType上。

在具体设计接口之前,我们要谈一下理论。如果把一个类CString的所有成员函数看作是一个集合a的话,CString实现的任意接口b中包含的全部函数集合c都是a的子集。所以,接口的实现其实不过就是把宿主对象的成员函数复制出来,按照某个规定的顺序重新排列一下而已。接口和基类之间的另外一个区别就是接口不需要宿主对象与之同构,而且不同的类型实现的相同接口之间的唯一相同的地方就是函数的排列顺序。

具体实现起来,我们就用一个额外的表来存放它,我们称之为InterfaceChain。

这样的结构已经可以支持IFormat fmt = (IFormat)new CString()语句了,但是CString str=(CString)fmt呢?出错了!所以我们要给每一个InterfaceChain元素添加一个owner,让他们指向CStringType,这样我们可以用CString str = (CString)fmt.owner来讲interface实例指针转换回对象指针。

以上设计的是我们的核心结构,而且随着未来特性的增加,会越来越复杂。这样的结构当然不能展示给用户使用,相反隐藏得越深越好。这一切还是要拜托神奇的macro来完成了。具体如何来封装和引用这些结构,下一次再讲。

posted @ 2009-12-03 12:32 老翅寒暑 阅读(1164) | 评论 (0)编辑

2009年12月1日

Crest的语法---宏的魔术汇演

上文完成了用纯C语言描述一个简单的对象结构的工作,因为要用例子表现,所以这次我们要来设计一下Crest的语法,也就是要看一下如果Crest最终能够成功完成的话,我们的编程代码会是一个什么样子。

最理想的面向对象语法当然是仿造C#、java这样的结构了,但是因为C语言要用头文件,所以估计最终的样式还是类似于C++。首先我们还是制定一个目标的样式,然后再去用Crest仿造实现。目标是这样的[代码1]:

class CString: CObject, IUnknown, IDispatch
{
 int length;
 char * buffer;
 
 public virtual void Format(char * format)
 {
 DoFormat(format);
 }
 
 public void DoFormat(char * format)
 {
 if( OnFormat != null ) OnFormat(format);
 }
 
 public abstract void OnFormat(char * format);
}

要想用Crest实现上面的结构,有几个问题要注意:

  1. this指针。所有的对象成员定义和调用都隐含有一个this指针
  2. 命名规范,CString的Format和CDateTime的Format肯定不是同一个东西,但是C语言不支持override,所以要保证成员函数不重名。

经过两天的断断续续工作,最终呈现结果如下[代码2]:

DECLARE_CLASS(CString)
 EXTENDS(CObject, IMPLEMENT2(IUnknown,IDispatch))
 
 DECLARE_FIELD(CString, int, length)
 DECLARE_FIELD(CString, char *, buffer)
 
 DECLARE_VIRTUAL1(CString, void, Format, const char * format)
 DECLARE_ABSTRACT1(CString, void, OnFormat,const char * format)
 
 DECLARE_METHOD1(CString, void, DoFormat,const char * format)
 
 DECLARE_CONSTRUCTOR(CString)
 DECLARE_DESTRUCTOR(CString)
END_DECLARE(CString);

这个风格是不是觉得有些累赘?bigtall开始也觉得不满意,但是后来发现借助C语言的Macro魔法,这样的结构反而是最简单的,或者说,比较爽!

在最终演化到这个样子的代码风格之前,我们可以手工来实现一个不用macro的版本,有对比才有真相啊!我们还是参考(代码1)部分,根据我们上文得到的经验,可以很轻松把代码给出来[代码3]:

 
struct Class_CString; 
typedef struct Class_CString CString;
void CString_Format (CString *self, const char * format);
void CString_OnFormat (CString *self, const char * format);
void CString_DoFormat (CString *self, const char * format);
void CString_constructor (CString *self);
void CString_destructor (CString *self);
 
struct Class_CString{
 int length;
 char * buffer;
 void (*Format) (CString *self, const char * format);
 void (*OnFormat) (CString *self, const char * format);
};
 

多了好多东西,写起来很麻烦,如果我们以后增加更多的特性的话,恐怕会成为噩梦。Crest要想让别人也去用,语法上面一定要让人觉得“合算”---增加一定的繁琐,但是得到的有用特性更多。为了实现(代码2)到(代码3)的转换,我们来看一下实际(代码2)的头文件定义:

 /* filename: macropure.h */
#if defined(DECLARATION) || defined(DEFINITION)
 
#include "CrestMacro.h"
 
DECLARE_CLASS(CString)
 .../*此处省略*/
END_DECLARE(CString);
 
#else
 #define DECLARATION
 #include "macropure.h"
 #undef DECLARATION
 
 #define DEFINITION
 #include "macropure.h"
 #undef DEFINITION
#endif
 
这里bigtall使用了大量的宏定义,而且用了一个很少用的特性:自己包含自己。通过自身的包含,结合#if..#else..#endif,我们实现了不同阶段的DECLARE_CLASS有不同的定义。这样做的结果就是写一次繁琐的定义,通过宏的转换,实现了完整的class的定义代码。这里可惜的是,要是#include也支持宏扩展的话,头文件可以更简单。另外bigtall还做了一个用cpp32预处理再包含.i文件的版本,因为可移植性的问题,否掉了。
 
以上讲的是.h头文件,对于.c文件,Crest的代码是这样的:
#include <stdio>
#include "macropure.h"
 
IMPL_VIRTUAL1(CString, void, Format, const char * format)
{
 REF_METHOD(CString, DoFormat)(self, format);
}
 
IMPL_ABSTRACT1(CString, void, OnFormat,const char * format)
{
 puts(format);
}
 
IMPL_METHOD1(CString, void, DoFormat,const char * format)
{
 if( self->OnFormat != 0 )
 self->OnFormat(self, format);
}
 
IMPL_CONSTRUCTOR(CString)
{
 self->length = 3;
 self->buffer = "abc";
 self->Format = REF_METHOD(CString, Format);
 self->OnFormat = REF_METHOD(CString, OnFormat);
}
 
IMPL_DESTRUCTOR(CString)
{
}
 
void main()
{
 CString str, *pStr;
 
 CONSTRUCT(CString, &str);
 NEW(CString, pStr);
 
 str.Format(&str, "abcdefg\n");
 pStr->Format(pStr, "cdefghijk\n");
 
 DELETE(CString, pStr);
 DESTRUCT(CString, &str);
}

 

上一篇:Crest简单对象的设计 (to be continue)

posted @ 2009-12-01 11:23 老翅寒暑 阅读(1135) | 评论 (1)编辑

2009年11月26日

Crest简单对象的设计

在我们开始Crest的设计之前,我们先看一段参考代码

using System;

using System.Collections.Generic;

 

public abstract class Bird{

protected String name;

public abstract String tweet();

public String getName(){return name;}

}

 

public class Cock : Bird{

public override String tweet(){return "woooooo";}

public virtual String walk(){return "cock walk";}

public void setName(String newName){ name = newName;}

}

 

 

public class MainClass

{

    public static void Main()

    {

        Bird bird = new Cock();

        Cock cock = new Cock();

        System.Console.WriteLine(bird.tweet());

    }

}

这是一段纯正的面向对象的代码,我们的话题就会沿着这一段代码展开。首先我们从设计Crest以支持最简单的对象。

简单对象

因为C语言的本身限制,所以我们要模拟一个类的定义只能使用struct。最简单的类当然就是空类了。我们的C代码如下:

struct CEmptyObject

{

}

然后我们要让我们的CEmptyObject类加入成员变量,也很简单:

struct CEmptyObject

{

    int salary;

};

再加入一个成员函数吧。我想加入一个getSalary,但是问题来了,怎么加呢?如果这样写:

int getSalary(){return salary;}

似乎是对的,但是C编译器报告salary找不到,如果把这行代码放到struct CEmptyObject中,同样也是编译错误[BCC32 Error] raw.c(143): E2200 Functions may not be part of a struct or union。实际上,大部分OO语言的实现都是类似的,我们也就不卖关子了,照搬如下:

    int getSalary(struct CEmptyObject * _this)

    {

        return _this->salary;

    }

所有我们代码中写的 xxx.getSalary() 类似的代码,都实际转化为getSalary(xxx)形式,如果大家熟悉C#的扩展函数,就更明白这一点。

简单对象的使用

设计好了简单对象,我们当然要用一下了,先看代码:

    int simpleMain()

    {

        struct CEmptyObject obj;

        

        printf("%d", getSalary(&obj));

    }

问题来了,构造函数呢?没关系,先凑合用一下吧,我们用C风格的初始化方法,代码如下:

    int simpleMain()

    {

        struct CEmptyObject obj = {3000};

        

        printf("%d", getSalary(&obj));

    }

运行正常!但是万一我们要用构造函数怎么办?没关系,构造函数其实就是一种特殊的成员函数而已,那就加上吧:

void CEmptyObject(struct CEmptyObject * _this, int salary)

{

    _this->salary = salary;

}

 

int simpleMain()

{

    struct CEmptyObject obj;

    CEmptyObject(&obj, 3000);

 

    printf("%d", getSalary(&obj));

}

运行还是正常!不过,OO语言里不是经常有new动作吗?我们现在模拟的对象,都实际创建在stack中,如果我们要用new创建到heap中呢?那就来模拟new吧!

struct CEmptyObject * new(size_t size)

{

    return (struct CEmptyObject *)malloc(size);

};

 

int simpleMain()

{

    struct CEmptyObject obj, *obj2;

    CEmptyObject(&obj, 3000);

 

    obj2 = new(sizeof(struct CEmptyObject));

    CEmptyObject(obj2, 4000);

 

    printf("%d", getSalary(&obj));

    printf("%d", getSalary(obj2));

}

运行,看起来正常!如果你打开监控,会有报告内存泄露,因为我们的new函数用malloc来分配了内存,而退出的时候我们没有释放它。所以我们需要同时实现一个delete函数,但是先别动手,我们要继续谈一下析构函数的问题。从本质上,析构函数也是一个特殊的成员函数,但是带来的问题是这个析构函数何时调用。对于C#、java等有垃圾收集功能的语言来说,析构函数会在销毁之前调用(深究则不然,后文会谈),C++则会在对象退出作用域之前自动调用,但是这里则要小心了,因为我们用手工调用。

void CEmptyObject(struct CEmptyObject * _this, int salary)

{

    _this->salary = salary;

}

 

void _CEmptyObject(struct CEmptyObject * _this)

{

_this->salary = 0;

}

 

struct CEmptyObject * new(size_t size)

{

    return (struct CEmptyObject *)malloc(size);

};

 

void delete(struct CEmptyObject *_this)

{

    _CEmptyObject(_this);

    free(_this);

}

 

int simpleMain()

{

    struct CEmptyObject obj, *obj2;

    CEmptyObject(&obj, 3000);

 

    obj2 = new(sizeof(struct CEmptyObject));

    CEmptyObject(obj2, 4000);

 

    printf("%d", getSalary(&obj));

    printf("%d", getSalary(obj2));

 

    delete(obj2);

    _CEmptyObject(&obj);

}

代码运行正常。可是大家是不是觉得这样太繁琐了阿?写这么多杂七杂八的东西,看起来一点都不简洁。而且bigtall一向认为一个优秀的程序员必定是"懒惰"的,他应该对任何形式的"重复工作"都无法容忍。所以我们需要用C语言的"宏定义"大法来改善代码的可读性。

上一篇: Crest-大家都来山寨一个GObject吧  下一篇: Crest的语法---宏的魔术汇演

posted @ 2009-11-26 11:45 老翅寒暑 阅读(1144) | 评论 (4)编辑

2009年11月23日

Crest-大家都来山寨一个GObject吧

感谢园子的两位博友给我们带来了和GObject相关的知识(参看《使用C语言进行面向对象的开发--GObject入门》系列和《玩玩 Vala》),受到他们的启发,决定也来仿造一个类似GObject的系统,用流行的话,就叫“山寨”了。希望bigtall这次也能做一个物美价廉质优轻便的“山寨”产品。

这次行动的目的有如下的几个:

  1. 揭开所谓“面向对象”编程语言的神秘面纱,带领大家到编程语言的深处旅游一下。
  2. 试探一下C语言在承载新语言特性方面的水深
  3. 展示一下C系列语言宏定义(Macro)的强大功效和不足
  4. 如果万一bigtall设计的新特性比原来的GObject要好些,说不定也能有些用场

首先bigtall要给我的“山寨”特性起一个合适的名字。嗯,我觉得“山寨”这个名字其实还是不错的,不过要翻译成英文可就不容易了,山寨==山顶别墅?首先看山顶,有解释说knap=the crest of a hill,看到crest比较顺眼,看看意思:“冠状物,(头盔上的)羽饰,(尤指山的)顶部”。不错!就是Crest了。

其次,我们要列出我们的需求,也就是要实现的“面向对象”特性的清单,不过bigtall也不知道到底我们能实现几个,我们“骑驴看唱本--走着瞧”吧。

  • 类(含duck type)
  • 接口
  • 类和接口的继承(包括类的单继承、类的多继承,接口的实现和继承,prototype继承)
  • 成员函数调用(包括普通成员、虚函数、纯虚函数)
  • 属性
  • 类型的检查和转换
  • 对象的创建和销毁(构造函数、析构函数)
  • 对象的内存分配和释放机制(new、delete)
  • 消息message、事件event、信号signal机制
  • 闭包Closure
  • 反射Reflection
  • 调试支持
  • 多线程

因为bigtall对函数式语言不熟悉,所以如果还有其他什么比较好玩的特性,请大家踊跃提供,因为我们这是属于研究探讨形式,所以也不必拘泥于能否最终实现。而且这个文章应该会写一个系列,bigtall希望展现一个完整的“设计、妥协、平衡”的完整过程给大家。

在进入正题之前,bigtall还想多说两句。在使用C语言的时候,我们一定要注意它的特点之一就是“没有异常处理”(setjump也许算)。这个特点带来的欢笑就是任何一个函数的出口都是设计好的,不会有异常Exception突然throw来中断代码的运行,简单;坏处就是判断出口代码会烦得要人命。

下一篇: Crest简单对象的设计

posted @ 2009-11-23 09:53 老翅寒暑 阅读(1254) | 评论 (2)编辑

2009年11月17日

漫谈公司管理之员工绩效和效率管理

一年一度的深圳高交会又开始了。从参加过前三届之后,发觉这种xx会的趋势都是一样的:一年不如一年。本来应该是政府搭台民间唱戏的,结果倒是政府唱戏越来越多,不入流的公司越来越多,跟“高新技术”无关的下三滥的东西越来越多。虽然排场越来越大,但无论是看的玩的拿的还是发的,都显得越来越小气。

甚至是越来越变态!因为本届高交会将展出一种采用人脸识别技术的“考勤系统”!!!!

几年前的老问题拿过来问大家一下:请问一个公司为什么要“考勤”

我这里没有标准答案,但是我有一个公式:员工产出=工作时间×工作效率。 《资本论》的剩余价值理论告诉我们,一个公司要更多盈利,就是要让员工在被雇佣的时间内产出尽可能的多的产品。为了达成这个目标,我们有两种方法:

1.增加工作时间

几乎所有的国产老板都在这么干。干的最狠的就是深圳关外的电子厂,当然一些著名的台巴子企业也包含在内。通过各种方法让员工连续干十几个小时,甚至连上厕所都不让。当然对付程序员不会如此,是另外一种叫做“加班”或者“自愿加班”的形式。

以上是揩油员工“自由时间”的方式,对于他们付工资买来的“八小时”时间,他们更不会放过了。于是就出现了一个专有名词“考勤”,以及和这个名词相关的一系列软件和硬件产业。恨不得要把这“八小时”计算精确到毫秒。

2.提高工作效率

人类最伟大的发明之一就是流水线生产,它就是一种提高工作效率的方法。关外的电子厂里除了用这个之外,还需要有“监工”来不断巡视,防止出现那些流水线上的小姑娘们因为手酸腰痛腿麻眼皮打架等任何因素导致手脚慢下来的情况出现。当然对付程序员也不能如此,这里又带出来另外一个问题:“什么样的员工才是效率最高的员工?

我得到的答案是“满意的员工效率最高”。喜爱钻牛角尖的朋友可以热烈讨论一下“满意”的区间取值问题,有时间我可以专门谈这个问题。但是对于广大的国产公营或私营老板来说,考虑这些的收益远比跟客户吃饭收益要小,所以似取一个平均值,用个简单的常数(比如0.5)来表示也凑合。所以大部分老板的眼睛又回到了“工作时间”上去了。

但是要知道,“工作效率”是可以为0的。尤其是软件行业更是如此。

影响一个员工工作效率的因素有很多,大的有工资奖金升迁问题,小的有一个电话、一个误删的文件、一个小的硬件故障甚至一个鼠标点击都能让程序员们瞬间就崩溃掉。所以要想让公司的员工效率都高起来,其实是一件很难的事情,对于那些口口“军事化”,声声“不要问xx能为你做什么,要问你能为xx做些什么”,矢口不提“人性化”的大小企业,更是一种几乎不可能的事情了。

所以,与其冒风险花代价去搞什么“人性化”,还不如买一个打卡钟划算。更重要的是,老板的身份没有降低,依然不需要去哄着员工。至于所谓的“潜在”的金钱流失,看不到也心不烦了。其实更深层的原因,是一旦不小心把员工效率提高上去了,哪能接到那么多的项目让他们做啊!

OK!那就让我们在变态的考勤道路上越走越远吧!过不了多久,市面上就会出现能够运用“生命探测仪”技术跟踪员工上厕所时间的考勤机了!

当然,依然会有很多同学希望去提高效率,尤其是广大有素质的老板想要去提高员工的工作效率,那么我们就来继续探讨一下如何提高效率的问题。

首先是培训。bigtall认为高效率的工作是一个技术,它至少需要当事人能够判断识别事情的优先级,能够运用处理各种事务的工具和方法,去克服自身影响效率的一些坏毛病。这些都无法在大学里学到,必须通过培训。如果有人想自学,可以去看看GTD(Get Things Done)方法、ZTD(Zen To Do)或者最新的Pomodoro方法。

其次是团队工作(Team Play)。但是如何组织好一个团队,并且让它有效地工作起来,也是一个项目管理中重大的课题。这里我推荐微软的MSF团队模型。以后我们可以再详细讨论。

第三是设计与验证。凡项目务必遵守“设计先行”的原则,并且让你的设计可以用令人信服的方法来验证其正确性。这样做比你在项目中期发现设计中的问题,要节约很多的时间。

第四就是来自google的“不作恶”原则。一个公司内的任何事情,必然都存在有一个让人感觉比较舒服 的解决方法,关键是有没有人愿意去找。

比如每个公司都存在的“工作时间上网” 的问题。前两天园子里有人为此把公司的网络断了;有些公司就是在网络上装了一些特别的软件,以此来监控员工的上网动态;还有些公司则给员工分配一些网络流量(比如UT);有些则根本就只能上局域网。每一种方法都有或多或少的一些问题,尤其是对程序员的工作会带来一定的不便。

我们对于“工作时间上网”的现象可以做一些深入的分析:

1. 如果大家都不忙,工作时间上点网我觉得正常,如果公司觉得时间不应该浪费,就应该安排各种活动,比如培训、沙龙、旅游等。

2. 如果只是这一个人不忙,其他人都忙,是不是工作分配不合理?还是这个人效率特高?前者要求PM重新分配工作,后者则是要通令嘉奖。

3. 如果这个人忙,但是还是工作时间上网。这个人是不是传说中的“网瘾”?要不要电击?还是他的自身工作编排出现了问题?还是偶尔心情不好?要不要帮助?

4. 如果公司形成了一股风气,并且导致工作效率普遍偏低,那么可以制定新的政策。

如果让bigtall来做,我会使用一个代理服务器(透明代理更好),并且用一个定期运行的脚本对代理日志进行分析,要分析这样几个要素:访问的流量分布,访问站点top10,每台机器访问的娱乐网站次数,等等。得到这些数据之后,我们就可以按照Play(游戏)的原则,用Play的规则来解决这些问题:

A)判断并在代理服务器上封杀工作时间访问娱乐网站,也可以修改内部网络的dns。 (基于原理是一个人经常上的网站都是有限的,封一个就少一个)

B)按照访问娱乐网站次数评选公司每周的“娱乐之星”,每周一给大家跳舞助兴。(如果想不跳就下次少上点网,这次要想不跳就在项目组请大家吃糖)

注:有人怕引起员工和公司的猫和老鼠的游戏,其实大可不必担心,去培训你的项目经理们吧,让他们把计划和跟踪做得更好一些就ok了。

 

 

 

 

 

posted @ 2009-11-17 01:02 老翅寒暑 阅读(2391) | 评论 (25)编辑

2009年10月9日

快速目录和文件遍历

     摘要: 遍历一个目录或者磁盘中的所有内容,常用的算法有两种:深度优先和广度优先。具体实现的时候,每种算法都可以有多种实现,一般来说,有递归和非递归两种。因为工作需要,所以bigtall实现了几种算法的对比。首先实现的是传统的深度优先的递归遍历算法,因为非递归算法和广度优先比较雷同所以没有实现。其次实现的是广度优先的递归和非递归算法,其中非递归广度算法采用一个先进先出的queue存储目录路径结果。最后实现的...  阅读全文

posted @ 2009-10-09 09:15 老翅寒暑 阅读(2689) | 评论 (7)编辑

2009年9月30日

清理winsxs的小工具

     摘要: 因为磁盘空间不够了,所以想起来清理一下系统垃圾文件,主要目标就是臭名昭著的winsxs目录。这个winsxs就是微软为了解决“dll hell”问题,结果是好比在windows系统里安置了一个毫无节制不断增大的“肿瘤”。听说微软研究院现在在研究这个问题,不过我想我的硬盘空间不够大,等不到这个补丁出来的时候,所以只好自己动手了。 winsxs目录下的文件都是系统要用的各种库文件,system32下存...  阅读全文

posted @ 2009-09-30 21:21 老翅寒暑 阅读(3520) | 评论 (11)编辑

2009年9月28日

怎样才是值得培养的程序员

     摘要: 在公司经常给员工做培训。培训的范围非常广泛,次数也非常多。从基本的html、js、各种网络知识、字符编码、加解密、常用软件架构编程,也经常会让他们自己去研究一些新的东西。但是一到真的要用的时候,总是让我非常生气。不仅他们培训过的东西不会,竟然还会根本就不记得,连msn里边详细写过的过程都会不记得。有时候想一下真的非常无奈,不是bigtall非要去找一个人做“徒弟”,可是连周...  阅读全文

posted @ 2009-09-28 09:10 老翅寒暑 阅读(480) | 评论 (11)编辑

2009年8月21日

从乘客丢钱包的报警处理过程谈职业化和专业化

     摘要: 昨天因为公交卡里边没钱了,所以去地铁里边充值,然后直接在附近公交车站上车回家。结果车没有开几米,一个美眉告诉司机说自己的钱包被盗了。于是司机建议美眉报警,然后就在下一站停了下来。于是我们被困了。等了大概二十分钟,警察叔叔过来了。按照bigtall有限的法律知识,警察不可能对我们搜身,这是侵犯人身权利的,但是至少会上车登记一下每个人的身份证,然后留下美眉回去做笔录,我们就可以继续行程了。可是实际的处...  阅读全文

posted @ 2009-08-21 20:20 老翅寒暑 阅读(228) | 评论 (0)编辑

2009年6月20日

一个统计服务器网络流量的小程序

     摘要: 因为工作需要,要统计一下服务器的网络吞吐量,并且出一个图表。在搜索网络吞吐量软件时候,看到这篇文章,于是决定用脚本来实现这个功能。bigtall在原文的启发下,做了一些修改,去掉了对unix工具的依赖,把它变成了一个纯的批处理文件。希望能给有需要的人帮助。 [代码]  阅读全文

posted @ 2009-06-20 00:09 老翅寒暑 阅读(518) | 评论 (3)编辑