关于作者

用户名:netfp
笔名:netfp
地区:
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言



最新评论

访问统计:
文章个数:8
评论个数:1
留言条数:0




Powered by BlogDriver 2.1

netfp

 

欢迎访问netfp的博客

文章

DIY电脑检测软件大集中
一、综合性检测分析  
1.AIDA32
这是一个综合性的系统检测分析工具,功能强大,易于上手。它可以详细的显示出PC每一个方面的信息。支持上千种(3400+)主板,支持上百种(360+)显卡,支持对并口/串口/U##这些PNP设备的检测,支持对各式各样的处理器的侦测。目前AIDA32已经有多语言的支持并且加入了病毒检测功能。AIDA32拥有数十种测试项目,主要包括CPU、主板、内存、传感器、GPU、显示器、多媒体、逻辑驱动器、光驱、ASPI、SMART、网络、DirectX、基准测试等等,支持的平台包括了Intel、AMD、VIA、nVIDIA、SIS等。 
注意:AIDA32有一个小BUG,它显示的nVIDIA的FX系列GPU的核心频率为其2D频率,目前还不能正确显示其3D频率。 
http://file.mydrivers.com/tools/tweak/AIDA323935.zip

2.SiSoftware Sandra 2004 
这是一套功能强大的系统分析评测工具,拥有超过30种以上的测试项目,主要包括有CPU、Drives、CD-ROM/DVD、Memory、SCSI、APM/ACPI、鼠标、键盘、网络、主板、打印机等。全面支持当前各种VIA、ALI芯片组和Pentium 4、AMD DDR平台。 
http://file.mydrivers.com/tools/twe...ra2004_9.89.zip

3.HWiNFO32 
电脑硬件检测软件。它主要可以显示出处理器、主板芯片组、PCMCIA接口、BIOS版本、内存等信息,另外HWiNFO还提供了对处理器、硬盘以及CD-ROM的性能测试功能。每个月都要出现许多我们知道或者不知道的电脑硬件,因此建议大家要经常下载这款测试软件的新版本。 
http://file.mydrivers.com/tools/tweak/hw32_141.exe

二、CPU检测
1.检测CPU是否被REMARK
(1)Intel Processor Frequency ID Utility 
  Intel Processor Frequency ID Utility是芯片业老大Intel发布的一款检测自家CPU的工具,权威性不容置疑。软件使用一种频率确定算法(速度检测)来确定处理器以何种内部速率运行,然后再检查处理器中的内部数据,并将此数据与检测到的#作频率进行比较,最终会将系统总体状态作为比较结果通知用户。 
  我们最关心的无非是两点:CPU的主频和倍频,CPU是否被超频。工具列出了“报告频率”和“预期频率”两项数据,前一项表示被测试CPU的当前运行速度,后一项表示被测试CPU出厂时所设计的最高#作速度,只要两者数据一致,即说明CPU未被超频。
http://aiedownload.intel.com/df-sup...06/fidchs27.msi"; 
http://dl.pconline.com.cn/html/1/7/dlid=527&dltypeid=1&pn=0&.html

2.CPU信息检测 
(1)CPU-Z 
该软件可以提供全面的CPU相关信息报告,包括有处理器的名称、厂商、时钟频率、核心电压、超频检测、CPU所支持的多媒体指令集,并且还可以显示出关于CPU的L1、L2的资料(大小、速度、技术),支持双处理器。目前的版本已经不仅可以侦测CPU的信息,包括主板、内存等信息的检测CPU-Z同样可以胜任。新版本增加了对AMD64处理器在64位Windows#作系统的支持,增加了对新处理器Celeron M、Pentium 4 Prescott的支持。 
http://file.mydrivers.com/tools/cpu/cpu-z-121.zip

(2)WCPUID 
WCPUID可以显示CPU的ID信息、内/外部时钟频率、CPU支持的多媒体指令集。重要的是它还具有“超频检测”功能。而且能显示CPU/主板芯片组/显示芯片的型号。有了它大家在购买电脑的时候就不用害怕被JS的打磨CPU所欺骗,因为它不到1MB的大小完全可以装进软盘,这样你就可以带着它去买CPU,相信JS看见了它就不敢再骗你了。 
http://file.mydrivers.com/tools/cpu/wcpu31a.exe

3.CPU稳定性测试 
(1)CPU Burn 
(2)Toast
(3)Prime 95 
在所有的拷机软件中,Prime 5 是公认比较BT的一款,其他大部分拷机软件和它比较起来,简直是小巫见大巫。Prime 95 和Super π有类似的地方,都是利用不停计算函数来达到测试系统稳定性的目地。不过Prime 95 的测试环境非常苛刻,即使能在Super π中顺利通过419万次测试的系统,也不见得能在Prime 95 中熬过1分钟。很多玩家用Prime 95 来测试超频后的CPU,并以此作为超频成功的证据。只要点击执行文件就可进入主界面。点击菜单栏“Option(选项)”中的“CPU”即可对测试进行设置。在这里,用户可以设置测试的时间、测试所使用的内存容量,可以看到测试的起始和结束时间、以及CPU的型号、实际频率以及缓存等信息。设置好以后点击单栏“Option(选项)”中的“Torture Test(稳定性测试)”就开始进行测试了。由于Prime95的系统稳定性测试消耗的系统资源并不多,用户可以在测试期间进行其它#作,这时Prime 95 会在系统托盘中生成一个红色的图标,代表测试正在顺利进行着,如果这个图标的颜色在测试还没有结束之前就变成黄色了,说明测试失败,你的系统没有达到Primr 95 所要求的稳定性。Prime 95 默认的测试时间为12小时,如果通过12小时的测试,那说明系统稳定;如果能通过24小时以上的测试,那么这个系统就基本不会因为稳定性而出现故障。
http://mersenne.org/gimps/p95v238.exe

(4)Hot CPU Tester Pro 
它特别适用于爱好超频的狂热者,支持MMX、SSE、AMD 3DNow!等技术,可以测试出L1和L2缓存、系统和内存的带宽、主板的芯片、多CPU的兼容性、CPU的稳定性、系统和内存总线,新版本支持最新的AMD Athlon 64和AMD Opteron CPU、支持超线程处理器,更换了新的界面,优化了测试功能。 
http://file.mydrivers.com/tools/tweak/hotcpu4.1.exe

(5)Super π
π是计算圆周率的软件,但它更适合用来测试CPU的稳定性。即使你的系统运行一天的Word、Photoshop都没有问题,而运行Super PI 也不一定能通过。可以说,Super π可以作为判断CPU稳定性的依据。使用方法:选择你要计算的位数(一般采用104万位),点击开始就可以了。视系统性能不同,运算时间也不相同,当然是时间越短约好。 
http://file.mydrivers.com/tools/tweak/superpi-8.zip

三、内存检测 
1.DocMemory 
“内存神医”是一种先进的电脑内存检测软件。它的友善的用户界面使用方便,#作灵活。它可以检测出所有电脑内存故障。“内存神医”使用严谨的测试算法和程序检测电脑基本内存和扩展内存。用户无需拆除内存条即可进行检测。从网上下载的初装软件可以生成一个自行起动的“内存神医”测试软盘。只要将这个软盘插入欲测电脑的软驱内并起动电脑即可开始内存检测。“内存神医”提供十种精密的内存检测程序,其中包括MATS,MARCH+,MARCHC-,以及CHECKERBOARD等。选用老化测试可以检测出95%以上内存软故障。用户可以使用鼠标器方便的选择检测程序和设定测试参数。 
http://file.mydrivers.com/tools/memory/DocMem1_45a.exe

2.MemTest 
这是一个可*的内存检测工具,通过对您的电脑进行储存与读取#作来分析检查内存情况。 
http://file.mydrivers.com/tools/tweak/MemTest2.5.zip

四、显示器检测 
1.CRT显示器检测 
Nokia Monitor Test 
不少朋友买了CRT显示器就直接接上去使用了,从未做过任何调试,也不知道自己的显示器是好是坏,现在我们可以用NOKIA Monitor Test这个程序来测试并调整你的显示器。这是一款Nokia公司出品的显示器测试软件,界面新颖、独特功能齐全,能够对几何失真、四角聚焦、白平衡、色彩还原能力等进行测试。 
http://file.mydrivers.com/tools/tweak/nokia.zip 

2.液晶显示器测试 
CheckScreen 
    这是一款非常专业的液晶显示器测试软件,可以很好地检测液晶显示器的色彩、响应时间、文字显示效果、有无坏点、视频杂讯的程度和调节复杂度等各项参数。 
    打开Monitors Matter CheckScreen程序后,切换到“LCD Display”标签页。这里列出了相关测试项目: 
    Colour:色阶测试,以3原色及高达1670万种的色阶画面来测试色彩的表现力,当然是无色阶最好啦,但大多数液晶显示器均会有一些偏色,少数采用四灯管技术的品牌这方面做得比较好,画面光亮、色彩纯正、鲜艳。 
    Crosstalk:边缘锐利度测试,屏幕显示对比极强的黑白交错画面,我们可以借此来检查液晶显示器色彩边缘的锐利程度。由于液晶显示器采用像素点发光的方式来显示画面,因此不会存在CRT显示器的聚焦问题。 
    Smearing:响应时间,测试画面是一个飞速运动的小方块,如果响应时间比较长,你就能看到小方块运行轨迹上有很多同样的色块,这就是所谓的拖尾现象。如果响应间比较短,我们所看到的色块数量也会少得多,因此笔者建议使用相机的自动连拍功能,将画面拍摄下来再慢慢观察。 
    Pixel Check:坏点检测,坏点数不大于3均属A级面板。 
    TracKing:视频杂讯检测,由于液晶显示较CRT显示器具有更强的抗干扰能力,即使稍有杂讯,采用“自动调节”功能后就可以将画面大小、时钟、相位等参数调节到理想状态。 
http://ftp1.mydown.com/home1/soft34/checkscreen1_2.zip
 
五、外部存储设备测试 
1.硬盘测试 
HD Tach 
这是一款硬盘物理性能测试软件,利用VXD特定模式来获得测试最大精确度的硬盘性能测试工具。这是目前硬盘测试必备的一款专门针对磁盘底层性能的测试工具软件,主要通过分段拷贝不同容量的数据到硬盘进行测试,它可以测试平均寻道时间、最大缓存读取时间和读写时间(最大、最小和平均)、硬盘的连续数据传输率、随机存取时间及突发数据传输率,它使用的场合并不仅仅只是针对硬盘,还可以用于软驱、ZIP驱动器测试。其中,平均读写时间是和平常应用最接近的情况。这是目前的最新版本,在新版本中加入了写测试和对WinNT4/2000/XP#作系统的支持。 
http://file.mydrivers.com/tools/tweak/HDTach270.exe

2.光驱测试 
(1)CD Speed 99 
这是一款综合的光盘驱动器性能测试软件,由ahead公司出品,它能够测试很多关于光盘和光盘驱动器的重要数据。比如光驱的传输率、搜索时间、CPU的占用率以及盘片的材质,最高支持速度,容量。与前一个版本比较,新版本加入了更多盘片检测信息,改良了DVD检测信息,优化了对DVD+R的兼容性问题……等很多的改变,推荐大家更新。 
http://file.mydrivers.com/tools/twe...CDSpeed_211.zip

六、性能测试软件 
1.综合性能测试 
(1)PCMark04 
这是一款测试计算机综合性能的工具,由鼎鼎大名的Futuremark出品,软件的风格和3DMark03如出一辙。整合的在线结果浏览器可以将你的测试结果与世界上最大的性能数据库进行对比。PCmark 04集易用性和专业性为一身,甚至适合刚刚上手的PC用户使用。PCMark 04的运行需要以下条件:必须使用Windows2000或Windows XP,必须安装Microsoft Internet Explorer 6,必须安装Microsoft Media Player 9,必须安装Microsoft Media Encoder 9,必须安装DirectX 9.0或以上版本。在HDD测试部分,这个版本解决了必须使用Windows XP测试的问题,现在在Windows2000下也可以执行此项测试。另外,该版本的PCMark04加入了对命令行支持,你可以使用命令方式来控制这款软件。 
http://file.mydrivers.com/tools/twe...04_patch110.exe

(2)WinBench 99 
WinBench 99是一个考察PC机的图形、磁盘、处理器和视频子系统在Windows环境中的性能的测试软件,它包括了下面几个测试项目:商用Graphics WinMark 99、商用Disk WinMark 99、高端Graphics WinMark 99、高端Disk WinMark 99、CPUmark 99/FPU WinMark。 
http://file.mydrivers.com/tools/tweak/wb9920g.exe 

2.CPU运算能力测试 
(1)科学计算能力测试 
① Super π 
Super π是一款计算圆周率的软件,但它更适合用来测试CPU的稳定性。下载地址见前面的链接。 
② ScienceMark 2.0 
ScienceMark 2.0可用来测试处理器的一级、二级缓存,以及内存的延迟时间。 
(2)CPU整数性能测试 
     ZD CPUmark 
(3)CPU整数、浮点性能测试 
     CPU BENCHMARK 

3.显卡性能测试 
(1)DirectX测试 
① 3DMark 2001SE Build 330 
FutureMark的3D Mark 系列测试软件凭籍着亮丽的画面和动感的音乐两大法宝,已经成为了标准的显卡测试软件,且深受大家的喜爱。简便的#作,直观的结果,与3D Winbench相比,3D Mark确实更能打动我们这些普通玩家。新版本里更加入了对DirectX 9.0、AGP 3.0 (AGP 8x)、日文和韩文#作系统、新型号的硬件产品(主要在图形芯片方面)的支持,修正了上个版本的一些BUG。该工具适合用于测试显卡的DX8性能。 
http://file.mydrivers.com/tools/tweak/3DMark2001SE.exe

② 3DMark03 Build 340 
为了避免驱动对测试软件作优化导致测试成绩的不公正现象,FutureMark推出了全新的3DMark03 Build340。该版本完全是为了防止驱动的特殊优化而推出的。今后,在FutureMark网站上将提供用做测试的推荐驱动,以帮助测试者得到更准确的成绩。还有一点大家需要注意,340版本推出后FutureMark将不再允许313、320或330版本3DMark03的成绩提交。该工具主要测试显卡的DX9性能。 
http://file.mydrivers.com/tools/tweak/3DMark03_340.exe
 
③ AquaMark3 
由于3DMark03引起的巨大争议,其公正性开始受到公众的置疑。这时候,由Massive Development开发的AquaMark3适时来到了我们的面前。不过,AquaMark3似乎同样受到了驱动作弊的困扰。 
http://file.mydrivers.com/tools/tweak/AquaMark3.exe

(2)OpenGL测试 
ViewPref是由著名的SPEC组织开发的一款OpenGL图形设备测试软件,在OpenGL测试领域内拥有极高的声誉,ViewPref的发展史很长最早可以追溯到1994年。ViewPref包含了大部分的OpenGL应用范围,主要用于测试系统在专业OpenGL应用中的速度。著名的OpenGL测试专用软件SPECviewperf今日终于公布了最新7.0版,新版本里在测试主题上偏向于应用型的软件,当然他还是一款免费的软件。该版本所包含的测试主要针对于显卡在真实软件中性能而设计,这些项目当然少不了CAD/CAM/CAE以及数码内容制作俗称DCC应用。SPECviewperf 7将所有的运行结果都以帧的形式表达,最终再进行重新的整理评分,以求得出一个最接近显卡在真实应用环境下的表现。SPECviewperf 7在原有6.1.2基础上加入了三个新的测试项目3DSMax[3dmax-01]、UniGraphics[ugs-01]及Pro/Enginner[proe-01]。 
http://file.mydrivers.com/tools/twe...cviewperf71.exe

- 作者: netfp 2005年11月27日, 星期日 21:09  回复(0) |  引用(0) 加入博采

typedef 的两种用法
typedef是c/c++代码中经常用到的一个关键字. 他的主要做用是给变量类型定义一个别名.
从而达到代码简化, 促进跨平台开发的目的.
下面是typedef的最经常的用法:

typedef struct{
  int a;
  int b;
}MY_TYPE;

这里把一个未命名结构直接取了一个叫MY_TYPE的别名, 这样如果你想定义结构的实例的时候就可以这样:
MY_TYPE tmp;

这是typedef的第一种用法. 比较简单. 就是 typedef 原变量类型 别名
相似的例子:
typedef  unsigned long DWORD;
typedef void far       *LPVOID; //void far *是原变量类型, 表示一个void 型指针(far 在32位系统里面已经没有意义了)
等等

typedef还有第二种用法. 可能这种用法初学者没有接触过.
比如:
typedef int (*MYFUN)(int, int);
这种用法一般用在给函数定义别名的时候.(其实质还是和上面的用法一样的)
上面的例子定义MYFUN 是一个函数指针, 函数类型是带两个int 参数, 返回一个int

在分析这种形式的定义的时候可以用下面的方法:
先去掉typedef 和别名, 剩下的就是原变量的类型.
比如上面的例子:
去掉typedef和MYFUN以后就剩:
int (*)(int, int)

读了我前面一课里面讨论的 <<细说如何确定一个变量的类型>>的朋友应该很容易就得出这个类型指的时是
一个函数指针, 函数类型是带两个int 参数, 返回一个int

- 作者: netfp 2005年11月12日, 星期六 12:57  回复(0) |  引用(0) 加入博采

C语言typedef的问题
1. 基本解释

  typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。

  在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

  至于typedef有什么微妙之处,请你接着看下面对几个问题的具体阐述。





  2. typedef & 结构的问题

  当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?莫非C语言不允许在结构中包含指向它自己的指针吗?请你先猜想一下,然后看下文说明:

typedef struct tagNode
{
 char *pItem;
 pNode pNext;
} *pNode;  

  答案与分析:

  1、typedef的最简单使用

typedef long byte_4;

  给已知数据类型long起个新名字,叫byte_4。

  2、 typedef与结构结合使用

typedef struct tagMyStruct
{
 int iNum;
 long lLength;
} MyStruct;

  这语句实际上完成两个操作:

  1) 定义一个新的结构类型

struct tagMyStruct
{
 int iNum;
 long lLength;
};

  分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。

  我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。

  2) typedef为这个新的结构起了一个名字,叫MyStruct。

typedef struct tagMyStruct MyStruct;

  因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。

  答案与分析

  C语言当然允许在结构中包含指向它自己的指针,我们可以在建立链表等数据结构的实现上看到无数这样的例子,上述代码的根本问题在于typedef的应用。

  根据我们上面的阐述可以知道:新结构建立的过程中遇到了pNext域的声明,类型是pNode,要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode。

  解决这个问题的方法有多种:

  1)、

typedef struct tagNode
{
 char *pItem;
 struct tagNode *pNext;
} *pNode;

  2)、

typedef struct tagNode *pNode;
struct tagNode
{
 char *pItem;
 pNode pNext;
};

  注意:在这个例子中,你用typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法。

  3)、规范做法:

struct tagNode
{
 char *pItem;
 struct tagNode *pNext;
};
typedef struct tagNode *pNode;

3. typedef & #define的问题

  有下面两种定义pStr数据类型的方法,两者有什么不同?哪一种更好一点?

typedef char *pStr;
#define pStr char *;  

  答案与分析:

  通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;

  在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。

  #define用法例子:

#define f(x) x*x
main( )
{
 int a=6,b=2,c;
 c=f(a) / f(b);
 printf("%d \n",c);
}

  以下程序的输出结果是: 36。

  因为如此原因,在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:

#define f(x) (x*x)

  当然,如果你使用typedef就没有这样的问题。

  4. typedef & #define的另一例

  下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;

  答案与分析:

  是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。

(注:关于const的限定内容问题,在本系列第二篇有详细讲解)。

  #define与typedef引申谈

  1) #define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。

  2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。

  5. typedef & 复杂的变量声明

  在编程实践中,尤其是看别人代码的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值,比如:

  下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?

>1:int *(*a[5])(int, char*);
>2:void (*b[10]) (void (*)());
>3. doube(*)() (*pa)[9];

  答案与分析:

  对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。

  (注:如果你对有些变量的声明语法感到难以理解,请参阅本系列第十篇的相关内容)。

>1:int *(*a[5])(int, char*);
//pFun是我们建的一个类型别名
typedef int *(*pFun)(int, char*);
//使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);
pFun a[5];

>2:void (*b[10]) (void (*)());
//首先为上面表达式蓝色部分声明一个新类型
typedef void (*pFunParam)();
//整体声明一个新类型
typedef void (*pFun)(pFunParam);
//使用定义的新类型来声明对象,等价于void (*b[10]) (void (*)());
pFun b[10];

>3. doube(*)() (*pa)[9];
//首先为上面表达式蓝色部分声明一个新类型
typedef double(*pFun)();
//整体声明一个新类型
typedef pFun (*pFunParam)[9];
//使用定义的新类型来声明对象,等价于doube(*)() (*pa)[9];
pFunParam pa;  

- 作者: netfp 2005年11月12日, 星期六 12:55  回复(1) |  引用(0) 加入博采

编程修养

编程修养
————
  
什么是好的程序员?是不是懂得很多技术细节?还是懂底层编程?还是编程速度比较快?
我觉得都不是。对于一些技术细节来说和底层的技术,只要看帮助,查资料就能找到,对
于速度快,只要编得多也就熟能生巧了。
  
我认为好的程序员应该有以下几方面的素质:
  
  1、有专研精神,勤学善问、举一反三。
  2、积极向上的态度,有创造性思维。
  3、与人积极交流沟通的能力,有团队精神。
  4、谦虚谨慎,戒骄戒燥。
  5、写出的代码质量高。包括:代码的稳定、易读、规范、易维护、专业。
  
这些都是程序员的修养,这里我想谈谈“编程修养”,也就是上述中的第5点。我觉得,如

果我要了解一个作者,我会看他所写的小说,如果我要了解一个画家,我会看他所画的图
画,如果我要了解一个工人,我会看他所做出来的产品,同样,如果我要了解一个程序员
,我想首先我最想看的就是他的程序代码,程序代码可以看出一个程序员的素质和修养,
程序就像一个作品,有素质有修养的程序员的作品必然是一图精美的图画,一首美妙的歌
曲,一本赏心悦目的小说。
  
我看过许多程序,没有注释,没有缩进,胡乱命名的变量名,等等,等等,我把这种人统
称为没有修养的程序,这种程序员,是在做创造性的工作吗?不,完全就是在搞破坏,他
们与其说是在编程,还不如说是在对源程序进行“加密”,这种程序员,见一个就应该开
除一个,因为他编的程序所创造的价值,远远小于需要在上面进行维护的价值。
  
程序员应该有程序员的修养,那怕再累,再没时间,也要对自己的程序负责。我宁可要那
种动作慢,技术一般,但有良好的写程序风格的程序员,也不要那种技术强、动作快的“
搞破坏”的程序员。有句话叫“字如其人”,我想从程序上也能看出一个程序员的优劣。
因为,程序是程序员的作品,作品的好坏直截关系到程序员的声誉和素质。而“修养”好
的程序员一定能做出好的程序和软件。
  
有个成语叫“独具匠心”,意思是做什么都要做得很专业,很用心,如果你要做一个“匠
”,也就是造诣高深的人,那么,从一件很简单的作品上就能看出你有没有“匠”的特性
,我觉得做一个程序员不难,但要做一个“程序匠”就不简单了。编程序很简单,但编出
有质量的程序就难了。
  
  
我在这里不讨论过深的技术,我只想在一些容易让人忽略的东西上说一说,虽然这些东西
可能很细微,但如果你不注意这些细微之处的话,那么他将会极大的影响你的整个软件质
量,以及整个软件程的实施,所谓“千里之堤,毁于蚁穴”。
  
“细微之处见真功”,真正能体现一个程序的功底恰恰在这些细微之处。
  
这就是程序员的——编程修养。我总结了在用C/C++语言(主要是C语言)进行程序写作上
的三十二个“修养”,通过这些,你可以写出质量高的程序,同时也会让看你程序的人渍
渍称道,那些看过你程序的人一定会说:“这个人的编程修养不错”。
  
    ————————————————————————
  
        01、版权和版本
        02、缩进、空格、换行、空行、对齐
        03、程序注释
        04、函数的[in][out]参数
        05、对系统调用的返回进行判断
        06、if 语句对出错的处理
        07、头文件中的#ifndef
        08、在堆上分配内存
        09、变量的初始化
        10、h和c文件的使用

        11、出错信息的处理
        12、常用函数和循环语句中的被计算量
        13、函数名和变量名的命名
        14、函数的传值和传指针
        15、修改别人程序的修养
        16、把相同或近乎相同的代码形成函数和宏
        17、表达式中的括号
        18、函数参数中的const
        19、函数的参数个数
        20、函数的返回类型,不要省略
        21、goto语句的使用
        22、宏的使用
        23、static的使用
        24、函数中的代码尺寸
        25、typedef的使用
        26、为常量声明宏
        27、不要为宏定义加分号
        28、||和&&的语句执行顺序
        29、尽量用for而不是while做循环
        30、请sizeof类型而不是变量
        31、不要忽略Warning
        32、书写Debug版和Release版的程序
        21、goto语究 使劲
        22、宏的使用
        23、static的使用
        24、函数中的代码尺寸
        25、typedef的使用
        26、为常量声明宏
        27、不要为宏定义加分号
        28、||和&&的语句执行顺序
        29、尽量用for而不是while做循环
        30、请sizeof类型而不是变量
        31、不要忽略Warning
        32、书写Debug版和Release版的程序
  
    ———————————————————————— 

1、版权和版本
———————
好的程序员会给自己的每个函数,每个文件,都注上版权和版本。
  
对于C/C++的文件,文件头应该有类似这样的注释:
/************************************************************************
*
*   文件名:network.c
*
*   文件描述:网络通讯函数集
*
*   创建人: Hao Chen, 2003年2月3日
*
*   版本号:1.0
*
*   修改记录:
*
*
************************************************************************/
  
而对于函数来说,应该也有类似于这样的注释:
  
/*================================================================
*
* 函 数 名:XXX
*
* 参    数:
*
*        type name [IN] : descripts
*
* 功能描述:
*
*        ..............
*
* 返 回 值:成功TRUE,失败FALSE
*
* 抛出异常:
*
* 作    者:ChenHao 2003/4/2
*
*
================================================================*/
  
这样的描述可以让人对一个函数,一个文件有一个总体的认识,对代码的易读性和易维护
性有很大的好处。这是好的作品产生的开始。
  
  
  
2、缩进、空格、换行、空行、对齐
————————————————
i) 缩进应该是每个程序都会做的,只要学程序过程序就应该知道这个,但是我仍然看过不
缩进的程序,或是乱缩进的程序,如果你的公司还有写程序不缩进的程序员,请毫不犹豫
的开除他吧,并以破坏源码罪起诉他,还要他赔偿读过他程序的人的精神损失费。缩进,
这是不成文规矩,我再重提一下吧,一个缩进一般是一个TAB键或是4个空格。(最好用TAB
键)
  
ii) 空格。空格能给程序代来什么损失吗?没有,有效的利用空格可以让你的程序读进来
更加赏心悦目。而不一堆表达式挤在一起。看看下面的代码:
  
    ha=(ha*128+*key++)%tabPtr->size;
  
    ha = ( ha * 128 + *key++ ) % tabPtr->size;
  
  
    有空格和没有空格的感觉不一样吧。一般来说,语句中要在各个操作符间加空格,函
数调用时,要以各个参数间加空格。如下面这种加空格的和不加的:
  
if ((hProc=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid))==NULL){
}
  
if ( ( hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid) ) == NULL ){
}
  
iii) 换行。不要把语句都写在一行上,这样很不好。如:
  
    for(i=0;i<len;i++) if((a[i]<'0'||a[i]>'9')&&(a[i]<'a'||a[i]>'z')) break;
  
    我拷,这种即无空格,又无换行的程序在写什么啊?加上空格和换行吧。
  
    for ( i=0; i<len; i++) {
        if ( ( a[i] < '0' || a[i] > '9' ) &&
             ( a[i] < 'a' || a[i] > 'z' ) ) {
            break;
        }
    }
  
  
    好多了吧?有时候,函数参数多的时候,最好也换行,如:
CreateProcess(
                  NULL,
                  cmdbuf,
                  NULL,
                  NULL,
                  bInhH,
                  dwCrtFlags,
                  envbuf,
                  NULL,
                  &siStartInfo,
                  &prInfo
                 );
  
    条件语句也应该在必要时换行:
  
    if ( ch >= '0' || ch <= '9' ||
         ch >= 'a' || ch <= 'z' ||
         ch >= 'A' || ch <= 'Z' )
  
  
iv) 空行。不要不加空行,空行可以区分不同的程序块,程序块间,最好加上空行。如:

  
    HANDLE hProcess;
    PROCESS_T procInfo;
  
    /* open the process handle */
    if((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)) == NULL)
    {
        return LSE_MISC_SYS;
    }
  
    memset(&procInfo, 0, sizeof(procInfo));
    procInfo.idProc = pid;
    procInfo.hdProc = hProcess;
    procInfo.misc |= MSCAVA_PROC;
  
    return(0);
  
v) 对齐。用TAB键对齐你的一些变量的声明或注释,一样会让你的程序好看一些。如:
  
typedef struct _pt_man_t_ {
    int     numProc;    /* Number of processes                 */
    int     maxProc;    /* Max Number of processes             */
    int     maxProc;    /* Max Number of processes             */
    int     numEvnt;    /* Number of events                    */
    int     maxEvnt;    /* Max Number of events                */
    HANDLE* pHndEvnt;   /* Array of events                     */
    DWORD   timeout;    /* Time out interval                   */
    HANDLE  hPipe;      /* Namedpipe                           */
    TCHAR   usr[MAXUSR];/* User name of the process            */
    int     numMsg;     /* Number of Message                   */
    int     Msg[MAXMSG];/* Space for intro process communicate */
} PT_MAN_T;
  
怎么样?感觉不错吧。
  
这里主要讲述了如果写出让人赏心悦目的代码,好看的代码会让人的心情愉快,读起代码
也就不累,工整、整洁的程序代码,通常更让人欢迎,也更让人称道。现在的硬盘空间这
么大,不要让你的代码挤在一起,这样它们会抱怨你虐待它们的。好了,用“缩进、空格
、换行、空行、对齐”装饰你的代码吧,让他们从没有秩序的土匪中变成一排排整齐有秩
序的正规部队吧。
  
  
  
  
3、程序注释
3、程序注释
——————
养成写程序注释的习惯,这是每个程序员所必须要做的工作。我看过那种几千行,却居然
没有一行注释的程序。这就如同在公路上驾车却没有路标一样。用不了多久,连自己都不
知道自己的意图了,还要花上几倍的时间才看明白,这种浪费别人和自己的时间的人,是
最为可耻的人。
  
是的,你也许会说,你会写注释,真的吗?注释的书写也能看出一个程序员的功底。一般
来说你需要至少写这些地方的注释:文件的注释、函数的注释、变量的注释、算法的注释
、功能块的程序注释。主要就是记录你这段程序是干什么的?你的意图是什么?你这个变
量是用来做什么的?等等。
  
不要以为注释好写,有一些算法是很难说或写出来的,只能意会,我承认有这种情况的时
候,但你也要写出来,正好可以训练一下自己的表达能力。而表达能力正是那种闷头搞技
术的技术人员最缺的,你有再高的技术,如果你表达能力不行,你的技术将不能得到充分
的发挥。因为,这是一个团队的时代。
  
好了,说几个注释的技术细节:
  
i) 对于行注释(“//”)比块注释(“/* */”)要好的说法,我并不是很同意。因为一
些老版本的C编译器并不支持行注释,所以为了你的程序的移植性,请你还是尽量使用块注
释。
  
  
ii) 你也许会为块注释的不能嵌套而不爽,那么你可以用预编译来完成这个功能。使用“#
if 0”和“#endif”括起来的代码,将不被编译,而且还可以嵌套。
  
  
  
  
4、函数的[in][out]参数
———————————
  
我经常看到这样的程序:
FuncName(char* str)
{
    int len = strlen(str);
    .....
}
  
char*
GetUserName(struct user* pUser)
{
    return pUser->name;
}
  
  
不!请不要这样做。
你应该先判断一下传进来的那个指针是不是为空。如果传进来的指针为空的话,那么,你
的一个大的系统就会因为这一个小的函数而崩溃。一种更好的技术是使用断言(assert)
,这里我就不多说这些技术细节了。当然,如果是在C++中,引用要比指针好得多,但你也
需要对各个参数进行检查。
  
写有参数的函数时,首要工作,就是要对传进来的所有参数进行合法性检查。而对于传出
的参数也应该进行检查,这个动作当然应该在函数的外部,也就是说,调用完一个函数后
,应该对其传出的值进行检查。
  
当然,检查会浪费一点时间,但为了整个系统不至于出现“非法操作”或是“Core Dump”
的系统级的错误,多花这点时间还是很值得的。
  
  
  
  
5、对系统调用的返回进行判断
——————————————
继续上一条,对于一些系统调用,比如打开文件,我经常看到,许多程序员对fopen返回的
指针不做任何判断,就直接使用了。然后发现文件的内容怎么也读出不,或是怎么也写不
进去。还是判断一下吧:
  
  
    fp = fopen("log.txt", "a");
    if ( fp == NULL ){
        printf("Error: open file error\n");
        return FALSE;
    }
  
其它还有许多啦,比如:socket返回的socket号,malloc返回的内存。请对这些系统调用
返回的东西进行判断。

6、if 语句对出错的处理
———————————
我看见你说了,这有什么好说的。还是先看一段程序代码吧。
  
    if ( ch >= '0' && ch <= '9' ){
        /* 正常处理代码 */
    }else{
        /* 输出错误信息 */
        printf("error ......\n");
        return ( FALSE );
    }
  
这种结构很不好,特别是如果“正常处理代码”很长时,对于这种情况,最好不要用else
。先判断错误,如:
  
    if ( ch < '0' || ch > '9' ){

        /* 输出错误信息 */
        printf("error ......\n");
        return ( FALSE );
    }
  
    /* 正常处理代码 */
    ......
  
  
这样的结构,不是很清楚吗?突出了错误的条件,让别人在使用你的函数的时候,第一眼
就能看到不合法的条件,于是就会更下意识的避免。
  
  
  
  
7、头文件中的#ifndef
——————————
千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两
个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件
,于是问题来了,大量的声明冲突。
  
还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用
管你的头文件会不会被多个文件引用
,你都要加上这个。一般格式是这样的:
  
    #ifndef  <标识>
    #define <标识>
  
    ......
    ......
  
    #endif
  
<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。
标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划
线,如:stdio.h
  
    #ifndef _STDIO_H_
    #define _STDIO_H_
  
    ......
  
    #endif
  
(BTW:预编译有多很有用的功能。你会用预编译吗?)
(BTW:预编译有多很有用的功能。你会用预编译吗?)
  
  
  
  
8、在堆上分配内存
—————————
可能许多人对内存分配上的“栈 stack”和“堆 heap”还不是很明白。包括一些科班出身
的人也不明白这两个概念。我不想过多的说这两个东西。简单的来讲,stack上分配的内存
系统自动释放,heap上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里
。stack一般是静态分配内存,heap上一般是动态分配内存。
  
由malloc系统函数分配的内存就是从堆上分配内存。从堆上分配的内存一定要自己释放。
用free释放,不然就是术语——“内存泄露”(或是“内存漏洞”)—— Memory Leak。
于是,系统的可分配内存会随malloc越来越少,直到系统崩溃。还是来看看“栈内存”和
“堆内存”的差别吧。
  
    栈内存分配
    —————
    char*
    AllocStrFromStack()
    {
        char pstr[100];

        return pstr;
    }
  
  
    堆内存分配
    —————
    char*
    AllocStrFromHeap(int len)
    {
        char *pstr;
  
        if ( len <= 0 ) return NULL;
        return ( char* ) malloc( len );
    }
  
对于第一个函数,那块pstr的内存在函数返回时就被系统释放了。于是所返回的char*什么
也没有。而对于第二个函数,是从堆上分配内存,所以哪怕是程序退出时,也不释放,所
以第二个函数的返回的内存没有问题,可以被使用。但一定要调用free释放,不然就是Mem
ory Leak!
  
在堆上分配内存很容易造成内存泄漏,这是C/C++的最大的“克星”,如果你的程序要稳定
,那么就不要出现Memory Leak。所以,我还是要在这里千叮咛万嘱付,在使用malloc系统
蛑龈叮谑褂胢alloc系统
函数(包括calloc,realloc)时千万要小心。
  
记得有一个UNIX上的服务应用程序,大约有几百的C文件编译而成,运行测试良好,等使用
时,每隔三个月系统就是down一次,搞得许多人焦头烂额,查不出问题所在。只好,每隔
两个月人工手动重启系统一次。出现这种问题就是Memery Leak在做怪了,在C/C++中这种
问题总是会发生,所以你一定要小心。一个Rational的检测工作——Purify,可以帮你测
试你的程序有没有内存泄漏。
  
我保证,做过许多C/C++的工程的程序员,都会对malloc或是new有些感冒。当你什么时候
在使用malloc和new时,有一种轻度的紧张和惶恐的感觉时,你就具备了这方面的修养了。
  
对于malloc和free的操作有以下规则:
  
1) 配对使用,有一个malloc,就应该有一个free。(C++中对应为new和delete)
2) 尽量在同一层上使用,不要像上面那种,malloc在函数中,而free在函数外。最好在同
一调用层上使用这两个函数。
3) malloc分配的内存一定要初始化。free后的指针一定要设置为NULL。
  
注:虽然现在的操作系统(如:UNIX和Win2k/NT)都有进程内存跟踪机制,也就是如果你
有没有释放的内存,操作系统会帮你释放。但操作系统依然不会释放你程序中所有产生了M
emory Leak的内存,所以,最好还是你自己来做这个工作。(有的时候不知不觉就出现Mem
ory Leak了,而且在几百万行的代码中找无异于海底捞针,Rational有一个工具叫Purify
蛐械拇胫姓椅抟煊诤5桌陶耄琑ational有一个工具叫Purify
,可能很好的帮你检查程序中的Memory Leak)
  
  
  
9、变量的初始化
————————
接上一条,变量一定要被初始化再使用。C/C++编译器在这个方面不会像JAVA一样帮你初始
化,这一切都需要你自己来,如果你使用了没有初始化的变量,结果未知。好的程序员从
来都会在使用变量前初始化变量的。如:
  
    1) 对malloc分配的内存进行memset清零操作。(可以使用calloc分配一块全零的内存

    2) 对一些栈上分配的struct或数组进行初始化。(最好也是清零)
  
不过话又说回来了,初始化也会造成系统运行时间有一定的开销,所以,也不要对所有的
变量做初始化,这个也没有意义。好的程序员知道哪些变量需要初始化,哪些则不需要。
如:以下这种情况,则不需要。
  
        char *pstr;  /* 一个字符串 */
        pstr = ( char* ) malloc( 50 );
        if ( pstr == NULL ) exit(0);
        strcpy( pstr, "Hello Wrold" );
        strcpy( pstr, "Hello Wrold" );
  
但如果是下面一种情况,最好进行内存初始化。(指针是一个危险的东西,一定要初始化

  
        char **pstr;  /* 一个字符串数组 */
        pstr = ( char** ) malloc( 50 );
        if ( pstr == NULL ) exit(0);
  
        /* 让数组中的指针都指向NULL */
        memset( pstr, 0, 50*sizeof(char*) );
  
而对于全局变量,和静态变量,一定要声明时就初始化。因为你不知道它第一次会在哪里
被使用。所以使用前初始这些变量是比较不现实的,一定要在声明时就初始化它们。如:
  
    Links *plnk = NULL;  /* 对于全局变量plnk初始化为NULL */
  
  
  
  
  
10、h和c文件的使用
—————————
—————————
H文件和C文件怎么用呢?一般来说,H文件中是declare(声明),C文件中是define(定义
)。因为C文件要编译成库文件(Windows下是.obj/.lib,UNIX下是.o/.a),如果别人要
使用你的函数,那么就要引用你的H文件,所以,H文件中一般是变量、宏定义、枚举、结
构和函数接口的声明,就像一个接口说明文件一样。而C文件则是实现细节。
  
H文件和C文件最大的用处就是声明和实现分开。这个特性应该是公认的了,但我仍然看到
有些人喜欢把函数写在H文件中,这种习惯很不好。(如果是C++话,对于其模板函数,在V
C中只有把实现和声明都写在一个文件中,因为VC不支持export关键字)。而且,如果在H
文件中写上函数的实现,你还得在makefile中把头文件的依赖关系也加上去,这个就会让
你的makefile很不规范。
  
最后,有一个最需要注意的地方就是:带初始化的全局变量不要放在H文件中!
  
例如有一个处理错误信息的结构:
  
char* errmsg[] = {
        /* 0 */       "No error",
        /* 1 */       "Open file error",
        /* 2 */       "Failed in sending/receiving a message",
        /* 3 */       "Bad arguments",
        /* 4 */       "Memeroy is not enough",
        /* 5 */       "Service is down; try later",

        /* 6 */       "Unknow information",
        /* 7 */       "A socket operation has failed",
        /* 8 */       "Permission denied",
        /* 9 */       "Bad configuration file format",
        /* 10 */      "Communication time out",
        ......
        ......
    };
  
请不要把这个东西放在头文件中,因为如果你的这个头文件被5个函数库(.lib或是.a)所
用到,于是他就被链接在这5个.lib或.a中,而如果你的一个程序用到了这5个函数库中的
函数,并且这些函数都用到了这个出错信息数组。那么这份信息将有5个副本存在于你的执
行文件中。如果你的这个errmsg很大的话,而且你用到的函数库更多的话,你的执行文件
也会变得很大。
  
正确的写法应该把它写到C文件中,然后在各个需要用到errmsg的C文件头上加上 extern
char* errmsg[]; 的外部声明,让编译器在链接时才去管他,这样一来,就只会有一个err
msg存在于执行文件中,而且,这样做很利于封装。
  
我曾遇到过的最疯狂的事,就是在我的目标文件中,这个errmsg一共有112个副本,执行文
件有8M左右。当我把errmsg放到C文件中,并为一千多个C文件加上了extern的声明后,所
有的函数库文件尺寸都下降了20%左右,而我的执行文件只有5M了。一下子少了3M啊。
  
[ 备注 ]
—————
有朋友对我说,这个只是一个特例,因为,如果errmsg在执行文件中存在多个副本时,可
以加快程序运行速度,理由是errmsg的多个复本会让系统的内存换页降低,达到效率提升
。像我们这里所说的errmsg只有一份,当某函数要用errmsg时,如果内存隔得比较远,会
产生换页,反而效率不高。
  
  
生副本导致执行文件尺寸变大,不仅增加了系统装载时间,也会让一个程序在内存中占更
多的页面。而对于errmsg这样数据,一般来说,在系统运行时不会经常用到,所以还是产
生的内存换页也就不算频繁。权衡之下,还是只有一份errmsg的效率高。即便是像logmsg
这样频繁使用的的数据,操作系统的内存调度算法会让这样的频繁使用的页面常驻于内存
,所以也就不会出现内存换页问题了。

11、出错信息的处理
—————————
你会处理出错信息吗?哦,它并不是简单的输出。看下面的示例:
  
    if ( p == NULL ){
        printf ( "ERR: The pointer is NULL\n" );
    }
  
告别学生时代的编程吧。这种编程很不利于维护和管理,出错信息或是提示信息,应该统
一处理,而不是像上面这样,写成一个“硬编码”。第10条对这方面的处理做了一部分说
明。如果要管理错误信息,那就要有以下的处理:
  
    /* 声明出错代码 */
    #define     ERR_NO_ERROR    0  /* No error                 */
    #define     ERR_OPEN_FILE   1  /* Open file error          */
    #define     ERR_SEND_MESG   2  /* sending a message error  */

    #define     ERR_BAD_ARGS    3  /* Bad arguments            */
    #define     ERR_MEM_NONE    4  /* Memeroy is not enough    */
    #define     ERR_SERV_DOWN   5  /* Service down try later   */
    #define     ERR_UNKNOW_INFO 6  /* Unknow information       */
    #define     ERR_SOCKET_ERR  7  /* Socket operation failed  */
    #define     ERR_PERMISSION  8  /* Permission denied        */
    #define     ERR_BAD_FORMAT  9  /* Bad configuration file   */
    #define     ERR_TIME_OUT   10  /* Communication time out   */
  
    /* 声明出错信息 */
    char* errmsg[] = {
        /* 0 */       "No error",
        /* 1 */       "Open file error",
        /* 2 */       "Failed in sending/receiving a message",
        /* 3 */       "Bad arguments",
        /* 4 */       "Memeroy is not enough",
        /* 5 */       "Service is down; try later",
        /* 6 */       "Unknow information",
        /* 7 */       "A socket operation has failed",
        /* 8 */       "Permission denied",
        /* 9 */       "Bad configuration file format",
        /* 10 */      "Communication time out",
        /* 10 */      "Communication time out",
    };
  
    /* 声明错误代码全局变量 */
    long errno = 0;
  
    /* 打印出错信息函数 */
    void perror( char* info)
    {
        if ( info ){
            printf("%s: %s\n", info, errmsg[errno] );
            return;
        }
  
        printf("Error: %s\n", errmsg[errno] );
    }
  
这个基本上是ANSI的错误处理实现细节了,于是当你程序中有错误时你就可以这样处理:
  
    bool CheckPermission( char* userName )
    {
        if ( strcpy(userName, "root") != 0 ){
            errno = ERR_PERMISSION_DENIED;

            return (FALSE);
        }
  
        ...
    }
  
    main()
    {
        ...
        if (! CheckPermission( username ) ){
            perror("main()");
        }
        ...
    }
  
一个即有共性,也有个性的错误信息处理,这样做有利同种错误出一样的信息,统一用户
界面,而不会因为文件打开失败,A程序员出一个信息,B程序员又出一个信息。而且这样
做,非常容易维护。代码也易读。
  
当然,物极必反,也没有必要把所有的输出都放到errmsg中,抽取比较重要的出错信息或
是提示信息是其关键,但即使这样,这也包括了大多数的信息。
  
  
  
  
  
12、常用函数和循环语句中的被计算量
—————————————————
看一下下面这个例子:
  
    for( i=0; i<1000; i++ ){
        GetLocalHostName( hostname );
        ...
    }
  
GetLocalHostName的意思是取得当前计算机名,在循环体中,它会被调用1000次啊。这是
多么的没有效率的事啊。应该把这个函数拿到循环体外,这样只调用一次,效率得到了很
大的提高。虽然,我们的编译器会进行优化,会把循环体内的不变的东西拿到循环外面,
但是,你相信所有编译器会知道哪些是不变的吗?我觉得编译器不可靠。最好还是自己动
手吧。
  
同样,对于常用函数中的不变量,如:
  
GetLocalHostName(char* name)
{
{
    char funcName[] = "GetLocalHostName";
  
    sys_log( "%s begin......", funcName );
    ...
    sys_log( "%s end......", funcName );
}
  
如果这是一个经常调用的函数,每次调用时都要对funcName进行分配内存,这个开销很大
啊。把这个变量声明成static吧,当函数再次被调用时,就会省去了分配内存的开销,执
行效率也很好。
  
  
  
  
13、函数名和变量名的命名
————————————
我看到许多程序对变量名和函数名的取名很草率,特别是变量名,什么a,b,c,aa,bb,cc,
还有什么flag1,flag2, cnt1, cnt2,这同样是一种没有“修养”的行为。即便加上好的注
释。好的变量名或是函数名,我认为应该有以下的规则:
  
    1) 直观并且可以拼读,可望文知意,不必“解码”。
    2) 名字的长度应该即要最短的长度,也要能最大限度的表达其含义。

    3) 不要全部大写,也不要全部小写,应该大小写都有,如:GetLocalHostName 或是
UserAccount。
    4) 可以简写,但简写得要让人明白,如:ErrorCode -> ErrCode,
ServerListener -> ServLisner,UserAccount -> UsrAcct 等。
    5) 为了避免全局函数和变量名字冲突,可以加上一些前缀,一般以模块简称做为前缀

    6) 全局变量统一加一个前缀或是后缀,让人一看到这个变量就知道是全局的。
    7) 用匈牙利命名法命名函数参数,局部变量。但还是要坚持“望文生意”的原则。
    8) 与标准库(如:STL)或开发库(如:MFC)的命名风格保持一致。
  
  
  
  
14、函数的传值和传指针
————————————
向函数传参数时,一般而言,传入非const的指针时,就表示,在函数中要修改这个指针把
指内存中的数据。如果是传值,那么无论在函数内部怎么修改这个值,也影响不到传过来
的值,因为传值是只内存拷贝。
  
什么?你说这个特性你明白了,好吧,让我们看看下面的这个例程:
  
void
void
GetVersion(char* pStr)
{
    pStr = malloc(10);
    strcpy ( pStr, "2.0" );
}
  
main()
{
    char* ver = NULL;
    GetVersion ( ver );
    ...
    ...
    free ( ver );
}
  
我保证,类似这样的问题是一个新手最容易犯的错误。程序中妄图通过函数GetVersion给
指针ver分配空间,但这种方法根本没有什么作用,原因就是——这是传值,不是传指针。
你或许会和我争论,我分明传的时指针啊?再仔细看看,其实,你传的是指针其实是在传
值。
  
  
  
  
15、修改别人程序的修养
———————————
  
当你维护别人的程序时,请不要非常主观臆断的把已有的程序删除或是修改。我经常看到
有的程序员直接在别人的程序上修改表达式或是语句。修改别人的程序时,请不要删除别
人的程序,如果你觉得别人的程序有所不妥,请注释掉,然后添加自己的处理程序,必竟
,你不可能100%的知道别人的意图,所以为了可以恢复,请不依赖于CVS或是SourceSafe这
种版本控制软件,还是要在源码上给别人看到你修改程序的意图和步骤。这是程序维护时
,一个有修养的程序员所应该做的。
  
如下所示,这就是一种比较好的修改方法:
  
    /*
     * ----- commented by haoel 2003/04/12 ------
     *
     *   char* p = ( char* ) malloc( 10 );
     *   memset( p, 0, 10 );
     */
  
    /* ------ Added by haoel   2003/04/12 ----- */
     char* p = ( char* )calloc( 10, sizeof char );
    /* ---------------------------------------- */
     *   char* p = 开始使劲) malloc( 10 );
     *   memset( p, 0, 10 );
     */
  
    /* ------ Added by haoel   2003/04/12 ----- */
     char* p = ( char* )calloc( 10, sizeof char );
    /* ---------------------------------------- */
    ...
  
当然,这种方法是在软件维护时使用的,这样的方法,可以让再维护的人很容易知道以前
的代码更改的动作和意图,而且这也是对原作者的一种尊敬。
  
以“注释 — 添加”方式修改别人的程序,要好于直接删除别人的程序。
-- 

16、把相同或近乎相同的代码形成函数和宏
—————————————————————
  
有人说,最好的程序员,就是最喜欢“偷懒”的程序,其中不无道理。
  
如果你有一些程序的代码片段很相似,或直接就是一样的,请把他们放在一个函数中。而
如果这段代码不多,而且会被经常使用,你还想避免函数调用的开销,那么就把他写成宏
吧。
  
千万不要让同一份代码或是功能相似的代码在多个地方存在,不然如果功能一变,你就要
修改好几处地方,这种会给维护带来巨大的麻烦,所以,做到“一改百改”,还是要形成
函数或是宏。
  
  
  
17、表达式中的括号
17、表达式中的括号
—————————
  
如果一个比较复杂的表达式中,你并不是很清楚各个操作符的忧先级,即使是你很清楚优
先级,也请加上括号,不然,别人或是自己下一次读程序时,一不小心就看走眼理解错了
,为了避免这种“误解”,还有让自己的程序更为清淅,还是加上括号吧。
  
比如,对一个结构的成员取地址:
  
    GetUserAge( &( UserInfo->age ) );
  
虽然,&UserInfo->age中,->操作符的优先级最高,但加上一个括号,会让人一眼就看明
白你的代码是什么意思。
  
再比如,一个很长的条件判断:
  
if ( ( ch[0] >= '0' || ch[0] <= '9' ) &&
     ( ch[1] >= 'a' || ch[1] <= 'z' ) &&
     ( ch[2] >= 'A' || ch[2] <= 'Z' )    )
  
括号,再加上空格和换行,你的代码是不是很容易读懂了?
  
  
  
18、函数参数中的const
———————————
  
对于一些函数中的指针参数,如果在函数中只读,请将其用const修饰,这样,别人一读到
你的函数接口时,就会知道你的意图是这个参数是[in],如果没有const时,参数表示[in/
out],注意函数接口中的const使用,利于程序的维护和避免犯一些错误。
  
虽然,const修饰的指针,如:const char* p,在C中一点用也没有,因为不管你的声明是
不是const,指针的内容照样能改,因为编译器会强制转换,但是加上这样一个说明,有利
于程序的阅读和编译。因为在C中,修改一个const指针所指向的内存时,会报一个Warning
。这会引起程序员的注意。
  
C++中对const定义的就很严格了,所以C++中要多多的使用const,const的成员函数,cons
t的变量,这样会对让你的代码和你的程序更加完整和易读。(关于C++的const我就不多说
了)
  
  
  
19、函数的参数个数(多了请用结构)
—————————————————
  
函数的参数个数最好不要太多,一般来说6个左右就可以了,众多的函数参数会让读代码的

人一眼看上去就很头昏,而且也不利于维护。如果参数众多,还请使用结构来传递参数。
这样做有利于数据的封装和程序的简洁性。
  
也利于使用函数的人,因为如果你的函数个数很多,比如12个,调用者很容易搞错参数的
顺序和个数,而使用结构struct来传递参数,就可以不管参数的顺序。
  
而且,函数很容易被修改,如果需要给函数增加参数,不需要更改函数接口,只需更改结
构体和函数内部处理,而对于调用函数的程序来说,这个动作是透明的。
  
  
  
  
20、函数的返回类型,不要省略
——————————————
  
我看到很多程序写函数时,在函数的返回类型方面不太注意。如果一个函数没有返回值,
也请在函数前面加上void的修饰。而有的程序员偷懒,在返回int的函数则什么不修饰(因
为如果不修饰,则默认返回int),这种习惯很不好,还是为了原代码的易读性,加上int
吧。
  
所以函数的返回值类型,请不要省略。
  
  
另外,对于void的函数,我们往往会忘了return,由于某些C/C++的编译器比较敏感,会报
一些警告,所以即使是void的函数,我们在内部最好也要加上return的语句,这有助于代
码的编译。
  
  
  
  
21、goto语句的使用
—————————
  
N年前,软件开发的一代宗师——迪杰斯特拉(Dijkstra)说过:“goto statment is
harmful !!”,并建议取消goto语句。因为goto语句不利于程序代码的维护性。
  
这里我也强烈建议不要使用goto语句,除非下面的这种情况:
  
  
    #define FREE(p) if(p) { \
                        free(p); \
                        p = NULL; \
                    }
  
    main()
    main()
    {
        char *fname=NULL, *lname=NULL, *mname=NULL;
  
        fname = ( char* ) calloc ( 20, sizeof(char) );
        if ( fname == NULL ){
goto ErrHandle;
        }
  
        lname = ( char* ) calloc ( 20, sizeof(char) );
        if ( lname == NULL ){
            goto ErrHandle;
        }
  
        mname = ( char* ) calloc ( 20, sizeof(char) );
        if ( mname == NULL ){
            goto ErrHandle;
        }
  
        ......
  
  
     ErrHandle:
     ErrHandle:
        FREE(fname);
        FREE(lname);
        FREE(mname);
        ReportError(ERR_NO_MEMOEY);
     }
  
也只有在这种情况下,goto语句会让你的程序更易读,更容易维护。(在用嵌C来对数据库
设置游标操作时,或是对数据库建立链接时,也会遇到这种结构)
  
  
  
  
22、宏的使用
——————
  
很多程序员不知道C中的“宏”到底是什么意思?特别是当宏有参数的时候,经常把宏和函
数混淆。我想在这里我还是先讲讲“宏”,宏只是一种定义,他定义了一个语句块,当程
序编译时,编译器首先要执行一个“替换”源程序的动作,把宏引用的地方替换成宏定义
的语句块,就像文本文件替换一样。这个动作术语叫“宏的展开”
  
使用宏是比较“危险”的,因为你不知道宏展开后会是什么一个样子。例如下面这个宏:
  
  
    #define  MAX(a, b)     a>b?a:b
  
当我们这样使用宏时,没有什么问题: MAX( num1, num2 ); 因为宏展开后变成
num1>num2?num1:num2;。 但是,如果是这样调用的,MAX( 17+32, 25+21 ); 呢,编译时
出现错误,原因是,宏展开后变成:17+32>25+21?17+32:25+21,哇,这是什么啊?
  
所以,宏在使用时,参数一定要加上括号,上述的那个例子改成如下所示就能解决问题了

  
    #define  MAX( (a), (b) )     (a)>(b)?(a):(b)
  
即使是这样,也不这个宏也还是有Bug,因为如果我这样调用 MAX(i++, j++); , 经过这
个宏以后,i和j都被累加了两次,这绝不是我们想要的。
  
所以,在宏的使用上还是要谨慎考虑,因为宏展开是的结果是很难让人预料的。而且虽然
,宏的执行很快(因为没有函数调用的开销),但宏会让源代码澎涨,使目标文件尺寸变
大,(如:一个50行的宏,程序中有1000个地方用到,宏展开后会很不得了),相反不能
让程序执行得更快(因为执行文件变大,运行时系统换页频繁)。
  
因此,在决定是用函数,还是用宏时得要小心。
--
  
。                 开始使劲
  
    #define  MAX( (a), (b) )     (a)>(b)?(a):(b)
  
即使是这样,也不这个宏也还是有Bug,因为如果我这样调用 MAX(i++, j++); , 经过这
个宏以后,i和j都被累加了两次,这绝不是我们想要的。
  
所以,在宏的使用上还是要谨慎考虑,因为宏展开是的结果是很难让人预料的。而且虽然
,宏的执行很快(因为没有函数调用的开销),但宏会让源代码澎涨,使目标文件尺寸变
大,(如:一个50行的宏,程序中有1000个地方用到,宏展开后会很不得了),相反不能
让程序执行得更快(因为执行文件变大,运行时系统换页频繁)。
  
因此,在决定是用函数,还是用宏时得要小心。
-- 

23、static的使用
————————
static关键字,表示了“静态”,一般来说,他会被经常用于变量和函数。一个static的
变量,其实就是全局变量,只不过他是有作用域的全局变量。比如一个函数中的static变
量:
  
char*
getConsumerName()
{
    static int cnt = 0;
  
    ....
    cnt++;
    ....
}
  
  
cnt变量的值会跟随着函数的调用次而递增,函数退出后,cnt的值还存在,只是cnt只能在
函数中才能被访问。而cnt的内存也只会在函数第一次被调用时才会被分配和初始化,以后
每次进入函数,都不为static分配了,而直接使用上一次的值。
  
对于一些被经常调用的函数内的常量,最好也声明成static(参见第12条)
  
但static的最多的用处却不在这里,其最大的作用的控制访问,在C中如果一个函数或是一
个全局变量被声明为static,那么,这个函数和这个全局变量,将只能在这个C文件中被访
问,如果别的C文件中调用这个C文件中的函数,或是使用其中的全局(用extern关键字)
,将会发生链接时错误。这个特性可以用于数据和程序保密。
  
  
  
24、函数中的代码尺寸
——————————
一个函数完成一个具体的功能,一般来说,一个函数中的代码最好不要超过600行左右,越
少越好,最好的函数一般在100行以内,300行左右的孙函数就差不多了。有证据表明,一
个函数中的代码如果超过500行,就会有和别的函数相同或是相近的代码,也就是说,就可
以再写另一个函数。
  
另外,函数一般是完成一个特定的功能,千万忌讳在一个函数中做许多件不同的事。函数
的功能越单一越好,一方面有利于函数的易读性,另一方面更有利于代码的维护和重用,

功能越单一表示这个函数就越可能给更多的程序提供服务,也就是说共性就越多。
  
虽然函数的调用会有一定的开销,但比起软件后期维护来说,增加一些运行时的开销而换
来更好的可维护性和代码重用性,是很值得的一件事。
  
  
25、typedef的使用
—————————
  
typedef是一个给类型起别名的关键字。不要小看了它,它对于你代码的维护会有很好的作
用。比如C中没有bool,于是在一个软件中,一些程序员使用int,一些程序员使用short,
会比较混乱,最好就是用一个typedef来定义,如:
  
    typedef char bool;
  
一般来说,一个C的工程中一定要做一些这方面的工作,因为你会涉及到跨平台,不同的平
台会有不同的字长,所以利用预编译和typedef可以让你最有效的维护你的代码,如下所示

  
    #ifdef SOLARIS2_5
      typedef boolean_t     BOOL_T;
    #else
    #else
      typedef int           BOOL_T;
    #endif
  
    typedef short           INT16_T;
    typedef unsigned short  UINT16_T;
    typedef int             INT32_T;
    typedef unsigned int    UINT32_T;
  
    #ifdef WIN32
      typedef _int64        INT64_T;
    #else
      typedef long long     INT64_T;
    #endif
  
    typedef float           FLOAT32_T;
    typedef char*           STRING_T;
    typedef unsigned char   BYTE_T;
    typedef time_t          TIME_T;
    typedef INT32_T         PID_T;
  
使用typedef的其它规范是,在结构和函数指针时,也最好用typedef,这也有利于程序的
易读和可维护性。如:

  
    typedef struct _hostinfo {
        HOSTID_T   host;
        INT32_T    hostId;
        STRING_T   hostType;
        STRING_T   hostModel;
        FLOAT32_T  cpuFactor;
        INT32_T    numCPUs;
        INT32_T    nDisks;
        INT32_T    memory;
        INT32_T    swap;
    } HostInfo;
  
  
    typedef INT32_T (*RsrcReqHandler)(
     void *info,
     JobArray *jobs,
     AllocInfo *allocInfo,
     AllocList *allocList);
  
C++中这样也是很让人易读的:
  
  
    typedef CArray<HostInfo, HostInfo&> HostInfoArray;
  
于是,当我们用其定义变量时,会显得十分易读。如:
  
    HostInfo* phinfo;
    RsrcReqHandler* pRsrcHand;
  
这种方式的易读性,在函数的参数中十分明显。
  
关键是在程序种使用typedef后,几乎所有的程序中的类型声明都显得那么简洁和清淅,而
且易于维护,这才是typedef的关键。
  
  
  
26、为常量声明宏
————————
最好不要在程序中出现数字式的“硬编码”,如:
  
    int user[120];
  
为这个120声明一个宏吧。为所有出现在程序中的这样的常量都声明一个
宏吧。比如TimeOut的时间,最大的用户数量,还有其它,只要是常量就应该声明成宏。如

果,突然在程序中出现下面一段代码,
  
    for ( i=0; i<120; i++){
        ....
    }
  
120是什么?为什么会是120?这种“硬编码”不仅让程序很读,而且也让程序很不好维护
,如果要改变这个数字,得同时对所有程序中这个120都要做修改,这对修改程序的人来说
是一个很大的痛苦。所以还是把常量声明成宏,这样,一改百改,而且也很利于程序阅读

  
    #define MAX_USR_CNT 120
  
    for ( i=0; i<MAX_USER_CNT; i++){
        ....
    }
  
这样就很容易了解这段程序的意图了。
  
有的程序员喜欢为这种变量声明全局变量,其实,全局变量应该尽量的少用,全局变量不
利于封装,也不利于维护,而且对程序执行空间有一定的开销,一不小心就造成系统换页
,造成程序执行速度效率等问题。所以声明成宏,即可以免去全局变量的开销,也会有速
,造成程序执行速度效率等问题。所以声明成宏,即可以免去全局变量的开销,也会有速
度上的优势。
  
  
27、不要为宏定义加分号
———————————
  
有许多程序员不知道在宏定义时是否要加分号,有时,他们以为宏是一条语句,应该要加
分号,这就错了。当你知道了宏的原理,你会赞同我为会么不要为宏定义加分号的。看一
个例子:
  
    #define MAXNUM 1024;
  
这是一个有分号的宏,如果我们这样使用:
  
    half = MAXNUM/2;
  
    if ( num < MAXNUM )
  
等等,都会造成程序的编译错误,因为,当宏展开后,他会是这个样子的:
  
    half = 1024;/2;
  
  
    if ( num < 1024; )
  
是的,分号也被展进去了,所以造成了程序的错误。请相信我,有时候,一个分号会让你
的程序出现成百个错误。所以还是不要为宏加最后一个分号,哪怕是这样:
  
    #define LINE    "================================="
  
    #define PRINT_LINE  printf(LINE)
  
    #define PRINT_NLINE(n)  while ( n-- >0 ) { PRINT_LINE; }
  
都不要在最后加上分号,当我们在程序中使用时,为之加上分号,
  
    main()
    {
        char *p = LINE;
        PRINT_LINE;
    }
  
这一点非常符合习惯,而且,如果忘加了分号,编译器给出的错误提示,也会让我们很容
易看懂的。
--
                   开始使劲
    #define PRINT_NLINE(n)  while ( n-- >0 ) { PRINT_LINE; }
  
都不要在最后加上分号,当我们在程序中使用时,为之加上分号,
  
    main()
    {
        char *p = LINE;
        PRINT_LINE;
    }
  
这一点非常符合习惯,而且,如果忘加了分号,编译器给出的错误提示,也会让我们很容
易看懂的。
-- 

28、||和&&的语句执行顺序
————————————
条件语句中的这两个“与”和“或”操作符一定要小心,它们的表现可能和你想像的不一
样,这里条件语句中的有些行为需要和说一下:
  
    express1 || express2
  
    先执行表达式express1如果为“真”,express2将不被执行,express2仅在express1
为“假”时才被执行。因为第一个表达式为真了,整个表达式都为真,所以没有必要再去
执行第二个表达式了。
  
    express1 && express2
  
    先执行表达式express1如果为“假”,express2将不被执行,express2仅在express1
为“真”时才被执行。因为第一个表达式为假了,整个表达式都为假了,所以没有必要再
去执行第二个表达式了。

  
  
于是,他并不是你所想像的所有的表达式都会去执行,这点一定要明白,不然你的程序会
出现一些莫明的运行时错误。
  
例如,下面的程序:
  
  
    if ( sum > 100 &&
         ( ( fp=fopen( filename,"a" ) ) != NULL )   {
  
         fprintf(fp, "Warring: it beyond one hundred\n");
         ......
    }
  
    fprintf( fp, " sum is %id \n", sum );
    fclose( fp );
  
本来的意图是,如果sum > 100 ,向文件中写一条出错信息,为了方便,把两个条件判断
写在一起,于是,如果sum<=100时,打开文件的操作将不会做,最后,fprintf和fclose就
会发现未知的结果。
  
  
再比如,如果我想判断一个字符是不是有内容,

- 作者: netfp 2005年11月12日, 星期六 12:50  回复(0) |  引用(0) 加入博采

四个受益终身的故事!

1  [转贴]四个受益终身的故事! 
  误会

  
  早年在美国阿拉斯加地方,有一对年轻人结婚,婚后生育,他的太太因难产而死,遗下一孩子。
  
  他忙生活,又忙于看家,因没有人帮忙看孩子,就训练一只狗,那狗聪明听话,能照顾小孩,咬着奶瓶喂奶给孩子喝,抚养孩子。
  
  有一天,主人出门去了,叫它照顾孩子。
  
  他到了别的乡村,因遇大雪,当日不能回来。第二天才赶回家,狗立即闻声出来迎接主人。他把房门开一看,到处是血,抬头一望,床上也是血,孩子不见了,狗在身边,满口也是血,主人发现这种情形,以为狗性发作,把孩子吃掉了,大怒之下,拿起刀来向着狗头一劈,把狗杀死了。
  
  之后,忽然听到孩子的声音,又见他从床下爬了出来,于是抱起孩子;虽然身上有血,但并未受伤。
  
  他很奇怪,不知究竟是怎么一回事,再看看狗身,腿上的肉没有了,旁边有一只狼,口里还咬着狗的肉;狗攘诵≈魅耍幢恢魅宋笊绷耍庹媸翘煜伦盍钊司娴奈蠡帷?
  
  【注解】:

  误会是在不了解、无理智;
  缺乏耐心、缺少思考;
  未能充分体谅对方、反省自己;
  感情极为冲动的情况下发生的事情。
  
  误会开始只是想到对方的千错万错,而没有站在对方的角度去考虑事情,

  故事中,小狗多么忠诚和善良,人的本性也应该是这样呀!
  难道人就喜欢去伤害别人,那于他有什么好处呢?

  而有时候,却因为面子的原因,使误会越陷越深,弄到不可收拾的地步……

  放下屠刀,立地成佛,怎样呢?

钉子

 
  有一个男孩有着很坏的脾气,于是他的父亲就给了他一袋钉子;并且告诉他,每当他发脾气的时候就钉一根钉子在后院的围篱上。
  
  第一天,这个男孩钉下了37根钉子。慢慢地每天钉下的数量减少了。他发现控制自己的脾气要比钉下那些钉子来得容易些。
  
  终于有一天这个男孩再也不会失去耐性乱发脾气,他告诉他的父亲这件事,父亲告诉他,现在开始每当他能控制自己的脾气的时候,就拔出一根钉子。
  
  一天天地过去了,最后男孩告诉他的父亲,他终于把所有钉子都拔出来了。
  
  父亲握着他的手来到后院说:你做得很好,我的好孩子。但是看看那些围篱上的洞,这些围篱将永远不能回复成从前。你生气的时候说的话将像这些钉子一样留下疤痕。如果你拿刀子捅别人一刀,不管你说了多少次对不起,那个伤口将永远存在。话语的伤痛就像真实的伤痛一样令人无法承受。。
  
  【注解】:
  
  人与人之间常常因为一些彼此无法释怀的坚持,而造成永远的伤害。

  如果我们都能从自己做起,开始宽容地看待他人,相信你一定能收到许多意想不到的结果....

  帮别人开启一扇窗,也就是让自己看到更完整的天空....

且慢下手

  
  大多数的同仁都很兴奋,因为单位里调来一位新主管,据说是个能人,专门被派来整顿业务;可是日一天天过去,新主管却毫无作为,每天彬彬有礼进办公室,便躲在里面难得出门,那些本来紧张得要死的坏份子,现在反而更猖獗了。
  
  他那里是个能人嘛!根本是个老好人,比以前的主管更容易唬!
  
  四个月过去,就在真正努力为新主管感到失望时,新主管却发威了--坏份子一律开革,能人则获得晋升。下手之快,断事之准,与四月表现保守的他,简直像是全然换个人。
  
  年终聚餐时,新主管在酒过三巡之后致词:

  【相信大家对我新到任期间的表现,和后来的大刀阔斧,一定感到不解,先听我说个故事吧:「我有位朋友,买了栋带着大院的房子,他一搬进去,就将那院子全面整顿,杂草树一律清除,改种自己新买的花卉,某日原先的屋主往访,进门大吃一惊的问:『那最名贵的牡丹哪里去了?』我这位朋友才发现,他竟然把牡丹当草给铲了。  
  后来他又买了一栋房子,虽然院子更是杂乱,他却是按兵不动,果然冬天以为是杂树的植物,春天里开了繁花;春天以为是野草的,夏天里成了锦蔟;半年都没有动静的小树,秋天居然红了叶。直到暮秋,它才真正认清哪些是无用的植物,而大力铲除,并使所有珍贵的草木得以保存。】
 
  
 
2  [转贴]四个受益终身的故事! 
 
  说到这儿,新主管举起杯来:

  【让我敬在座的每一位,因为如果这办公室是个花园,你们就都是其间的珍木,
  珍木不可能一年到头开花结果,只有经过长期的观察才认得出啊!】

宽大

  
  这是一个来自越战归来的士兵的故事。他从旧金山打电话给他的父母,告诉他们:「爸妈,我回来了,可是我有个不情之请。我想带一个朋友同我一起回家。」「当然好啊!」他们回答「我们会很高兴见到的。」
  
  不过儿子又继续下去「可是有件事我想先告诉你们,他在越战里受了重伤,少了一条胳臂和一只脚,他现在走投无路,我想请他回来和我们一起生活。」
  
  「儿子,我很遗撼,不过或许我们可以帮他找个安身之处。」父亲又接着说「儿子,你不知道自己在说些什么。像他这样残障的人会对我们的生活造成很大的负担。我们还有自己的生活要过,不能就让他这样破坏了。我建议你先回家然后忘了他,他会找到自己的一片天空的。」就在此时儿子挂上了电话,他的父母再也没有他的消息了。
  
  几天后,这对父母接到了来自旧金山警局的电话,告诉他们亲爱的儿子已经坠楼身亡了。警方相信这只是单纯的自杀案件。于是他们伤心欲绝地飞往旧金山,并在警方带领之下到停尸间去辨认儿子的遗体。
  
  那的确是他们的儿子没错,但惊讶的是儿子居然,只有一条胳臂和一条腿。
  
  故事中的父母就和我们大多数人一样。要去喜爱面貌姣好或谈吐风趣的人很容易,但是要喜欢那些造成我们不便和不快的人却太难了。我们总是宁愿和那些不如我们健康,美丽或聪明的人保持距离。
  
  然而感谢上帝,有些人却不会对我们如此残酷。他们会无怨无悔地爱我们,不论我们多么糟总是愿意接纳我们。今晚在你入睡之前,向上帝祷告请他赐给你力量去接纳他人,不论他们是怎么样的人;请他帮助我们了解那些不同于我们的人。
  
  每个人的心里都藏着一种神奇的东西称为【爱】,你不知道它究竟是如何发生何时发生,但你却知道它总会带给我们特殊的礼物。
 
  你也会了解【爱】是上帝给我们最珍贵的赠与!

  朋友就像是稀奇的宝物。他们带来欢笑,激励我们成功。他们倾听我们内心的话,与我们分享每一句赞美。他们的心房永远为我们而敞开。

  现在就告诉你的朋友:你有多在乎他们。

  或许,你的朋友只是个陌生人,你们只有一面之识。

  其实,再久远的朋友也只是一面之识而已……

  朋友,您一路看下来之后;一定有一些的感触吧。

  那么,在对别人有所决定与判断之前,首先,请想想这是否是一个「误会」,然后,请考虑您是否一定要钉下这个「钉子」,如果可以的话,请「且慢下手」。
  
  因为,当您对别人「宽大」之时,即是对您自己宽大。

  宽大即是【爱】。
 
 

- 作者: netfp 2005年11月9日, 星期三 18:11  回复(0) |  引用(0) 加入博采

大家好
netfp的博客开通了

- 作者: netfp 2005年11月9日, 星期三 15:14  回复(0) |  引用(0) 加入博采