卓's profile成都,又是成都PhotosBlogListsMore Tools Help

Blog


    June 11

    VS的正则表达式工具还不错

    今天要对一组文本数据做处理,去掉一些不必要的,自然就想到了使用正则表达式。首先是用UltraEdit来做,发现很不方便,支持的规则比较少。例如,查找两位数字,只能用[0-9][0-9],不能使用类似[0-9]^2的模式。而且,不能对查找的字串分组,例如这样的用法是不合法的{12}+。
    要实现我的目的,用这样的语法,匹配模式会写的很啰嗦,决定换个工具试试。选了M$的VS,一查才发现,功能还蛮丰富的,以前干这活都用的EditPlus,用VS看来会更方便一点。抄录MSDN相关部分如下:
    Expression Syntax Description

    Any character

    .

    Matches any single character except a line break.

    Zero or more

    *

    Matches zero or more occurrences of the preceding expression, making all possible matches.

    One or more

    +

    Matches at least one occurrence of the preceding expression.

    Beginning of line

    ^

    Anchors the match string to the beginning of a line.

    End of line

    $

    Anchors the match string to the end of a line.

    Beginning of word

    <

    Matches only when a word begins at this point in the text.

    End of word

    >

    Matches only when a word ends at this point in the text.

    Line break

    \n

    Matches a platform-independent line break. In a Replace expression, inserts a line break.

    Any one character in the set

    []

    Matches any one of the characters within the []. To specify a range of characters, list the starting and ending character separated by a dash (-), as in [a-z].

    Any one character not in the set

    [^...]

    Matches any character not in the set of characters following the ^.

    Or

    |

    Matches either the expression before or the one after the OR symbol (|). Mostly used within a group. For example, (sponge|mud) bath matches "sponge bath" and "mud bath."

    Escape

    \

    Matches the character that follows the backslash (\) as a literal. This allows you to find the characters used in regular expression notation, such as { and ^. For example, \^ Searches for the ^ character.

    Tagged expression

    {}

    Matches text tagged with the enclosed expression.

    C/C++ Identifier

    :i

    Matches the expression ([a-zA-Z_$][a-zA-Z0-9_$]*).

    Quoted string

    :q

    Matches the expression (("[^"]*")|('[^']*')).

    Space or Tab

    :b

    Matches either space or tab characters.

    Integer

    :z

    Matches the expression ([0-9]+).

    The list of all regular expressions that are valid in Find and Replace operations is longer than can be displayed in the Reference List. You can also insert any of the following regular expressions into a Find what string:

    Expression Syntax Description

    Minimal — zero or more

    @

    Matches zero or more occurrences of the preceding expression, matching as few characters as possible.

    Minimal — one or more

    #

    Matches one or more occurrences of the preceding expression, matching as few characters as possible.

    Repeat n times

    ^n

    Matches n occurrences of the preceding expression. For example, [0-9]^4 matches any 4-digit sequence.

    Grouping

    ()

    Groups a subexpression.

    nth tagged text

    \n

    In a Find or Replace expression, indicates the text matched by the nth tagged expression, where n is a number from 1 to 9.

    In a Replace expression, \0 inserts the entire matched text.

    Right-justified field

    \(w,n)

    In a Replace expression, right-justifies the nth tagged expression in a field at least w characters wide.

    Left-justified field

    \(-w,n)

    In a Replace expression, left-justifies the nth tagged expression in a field at least w characters wide.

    Prevent match

    ~(X)

    Prevents a match when X appears at this point in the expression. For example, real~(ity) matches the "real" in "realty" and "really," but not the "real" in "reality."

    Alphanumeric character

    :a

    Matches the expression ([a-zA-Z0-9]).

    Alphabetic character

    :c

    Matches the expression ([a-zA-Z]).

    Decimal digit

    :d

    Matches the expression ([0-9]).

    Hexadecimal digit

    :h

    Matches the expression ([0-9a-fA-F]+).

    Rational number

    :n

    Matches the expression (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+)).

    Alphabetic string

    :w

    Matches the expression ([a-zA-Z]+).

    Escape

    \e

    Unicode U+001B.

    Bell

    \g

    Unicode U+0007.

    Backspace

    \h

    Unicode U+0008.

    Tab

    \t

    Matches a tab character, Unicode U+0009.

    Unicode character

    \x#### or \u####

    Matches a character given by Unicode value where #### is hexadecimal digits. You can specify a character outside the Basic Multilingual Plane (that is, a surrogate) with the ISO 10646 code point or with two Unicode code points giving the values of the surrogate pair.

    September 26

    SOA

    面向服务的体系结构(Service-oriented architecture)是构造分布式系统的应用程序的方法。它将应用程序功能作为服务发送最终用户或者其他服务

    它采用开放标准、与软件资源进行交互并采用表示的标准方式。

    Why SOA?

    企业系统的架构师认为SOA能够帮助业务迅速和高效地响应变化的市场条件[1] . 服务导向的架构在宏观(服务)上,而不是在微观上(对象)提高了重用性。同时,服务导向的架构可以简化与传统系统的互连和使用。

    在某种意义上说,服务导向的架构可以被认为是一种演化,而不是革命。它捕捉到了之前体系架构的许多最佳实践或实际应用。比如在通信系统中,近年来进展有限的解决方案多采用完全静态的绑定来与网络中的其他设备沟通,但若正式采用SOA方式,解决方案就更能妥善定位,进而突显定义明确且可高度跨平台操作接口的重要性。

    有些人质疑服务导向的架构是不是1970年代模块化编程,1980年代的面向事件设计,1990年代的基于接口/构件设计的一种复兴?(1990s). 服务导向的架构提升了将用户从服务实现分开的目标。服务可以运行在不同的服务器上,并通过网络被访问。 这也大大增加了服务的重用.

    SOA的原则

    [2] 以下指导原则是开发,维护和使用SOA的基本原则[3]

    • 重用, 粒度, 模组性, 可组合型, 构件化以及互操作性
    • 符合标准(通用的或行业的)
    • 服务的识别和分类,提供和发布,监控和跟踪。

    下面是一些特定的体系架构原则

    • 服务封装
    • 服务松耦合(Loosely coupled) - 服务之间的关系最小化,只是互相知道。
    • 服务契约 - 服务按照服务描述文档所定义的服务契约行事。
    • 服务抽象 - 除了服务契约中所描述的内容,服务将对外部隐藏逻辑。
    • 服务的重用性 - 将逻辑分布在不同的服务中,以提高服务的重用性。
    • 服务的可组合性 - 一组服务可以协调工作并组合起来形成一个组合服务。
    • 服务自治 – 服务对所封装的逻辑具有控制权
    • 服务无状态 – 服务将一个活动所需保存的资讯最小化。
    • 服务的可被发现性 – 服务需要对外部提供描述资讯,这样可以通过现有的发现机制发现并访问这些服务。[4]

    除此以外,在定义一个SOA实现时,还需要考虑以下因素:

    • 生命周期管理
    • 有效使用系统资源
    • 服务成熟度和性能

     面向服务的架构和Web服务协议

    面向服务的架构通常被定义为通过Web服务协议栈暴露的服务 . 与SOA相关的Web服务的标准主要有:
    • XML - 一种标记语言,用于以文档格式描述消息中的数据。
    • HTTP (或HTTPS) - 客户端和服务端之间用于传送信息而发送请求/回复的协议。
    • SOAP - 在计算机网络上交换基于XML的消息的协议,通常是用HTTP。
    • WSDL (Web服务描述语言) - 基于XML的描述语言,用于描述与服务交互所需的服务的公共借口,协议绑定,消息格式。
    • UDDI (是统一描述、发现和集成) - 基于XML的注册协议,用于发布WSDL并允许第三方发现这些服务。

    注意,一个系统要成为面向服务的系统并不需要这些协议,比如一些面向服务的系统可以通过CORBA实现。

     参考文献

    1. Christopher Koch A New Blueprint For The Enterprise, CIO Magazine, Mar 1 2005
    2. Norbert Bieberstein Service-Oriented Architecture Compass 2006
    3. Yvonne Balzer 改进您的 SOA 专案规划, IBM, 2004年8月1日
    4. Thomas Erl Serviceorientation.org - About the Principles, 2005-2006

    July 27

    函数调用约定

     
    在C语言中,假设我们有这样的一个函数:

    int function(int a,int b)

    调用时只要用result = function(1,2)这样的方式就可以使用这个函数。但是,当高级
    语言被编译成计算机可以识别的机器码时,有一个问题就凸现出来:在CPU中,计算机没
    有办法知道一个函数调用需要多少个、什么样的参数,也没有硬件可以保存这些参数。
    也就是说,计算机不知道怎么给这个函数传递参数,传递参数的工作必须由函数调用者
    和函数本身来协调。为此,计算机提供了一种被称为栈的数据结构来支持参数传递。

    栈是一种先进后出的数据结构,栈有一个存储区、一个栈顶指针。栈顶指针指向堆栈中
    第一个可用的数据项(被称为栈顶)。用户可以在栈顶上方向栈中加入数据,这个操作
    被称为压栈(Push),压栈以后,栈顶自动变成新加入数据项的位置,栈顶指针也随之修
    改。用户也可以从堆栈中取走栈顶,称为弹出栈(pop),弹出栈后,栈顶下的一个元素变
    成栈顶,栈顶指针随之修改。

    函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得
    数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈
    恢复原装。

    在参数传递中,有两个很重要的问题必须得到明确说明:

    当参数个数多于一个时,按照什么顺序把参数压入堆栈
    函数调用后,由谁来把堆栈恢复原装
    在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:

    stdcall
    cdecl
    fastcall
    thiscall
    naked call
    stdcall调用约定
    stdcall很多时候被称为pascal调用约定,因为pascal是早期很常见的一种教学用计算机
    程序设计语言,其语法严谨,使用的函数调用约定就是stdcall。在Microsoft C++系列
    的C/C++编译器中,常常用PASCAL宏来声明这个调用约定,类似的宏还有WINAPI和CALLB
    ACK。

    stdcall调用约定声明的语法为(以前文的那个函数为例):

    int __stdcall function(int a,int b)

    stdcall的调用约定意味着:1)参数从右向左压入堆栈,2)函数自身修改堆栈 3)函数
    名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸

    以上述这个函数为例,参数b首先被压栈,然后是参数a,函数调用function(1,2)调用处
    翻译成汇编语言将变成:


    push 2 第二个参数入栈
    push 1 第一个参数入栈
    call function 调用参数,注意此时自动把cs:eip入栈


    而对于函数自身,则可以翻译为:


    push ebp 保存ebp寄存器,该寄存器将用来保存堆栈的栈顶指针,可以在函数退出
    时恢复
    mov ebp,esp 保存堆栈指针
    mov eax,[ebp + 8H] 堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向
    a
    add eax,[ebp + 0CH] 堆栈中ebp + 12处保存了b
    mov esp,ebp 恢复esp
    pop ebp
    ret 8

    而在编译时,这个函数的名字被翻译成_function@8

    注意不同编译器会插入自己的汇编代码以提供编译的通用性,但是大体代码如此。其中
    在函数开始处保留esp到ebp中,在函数结束恢复是编译器常用的方法。

    从函数调用看,2和1依次被push进堆栈,而在函数中又通过相对于ebp(即刚进函数时的
    堆栈指针)的偏移量存取参数。函数结束后,ret 8表示清理8个字节的堆栈,函数自己
    恢复了堆栈。

    cdecl调用约定
    cdecl调用约定又称为C调用约定,是C语言缺省的调用约定,它的定义语法是:


    int function (int a ,int b) //不加修饰就是C调用约定
    int __cdecl function(int a,int b)//明确指出C调用约定


    在写本文时,出乎我的意料,发现cdecl调用约定的参数压栈顺序是和stdcall是一样的
    ,参数首先由有向左压入堆栈。所不同的是,函数本身不清理堆栈,调用者负责清理堆
    栈。由于这种变化,C调用约定允许函数的参数的个数是不固定的,这也是C语言的一大
    特色。对于前面的function函数,使用cdecl后的汇编码变成:


    调用处
    push 1
    push 2
    call function
    add esp,8 注意:这里调用者在恢复堆栈
    被调用函数_function处
    push ebp 保存ebp寄存器,该寄存器将用来保存堆栈的栈顶指针,可以在函数退出
    时恢复
    mov ebp,esp 保存堆栈指针
    mov eax,[ebp + 8H] 堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向
    a
    add eax,[ebp + 0CH] 堆栈中ebp + 12处保存了b
    mov esp,ebp 恢复esp
    pop ebp
    ret 注意,这里没有修改堆栈


    MSDN中说,该修饰自动在函数名前加前导的下划线,因此函数名在符号表中被记录为_f
    unction,但是我在编译时似乎没有看到这种变化。

    由于参数按照从右向左顺序压栈,因此最开始的参数在最接近栈顶的位置,因此当采用
    不定个数参数时,第一个参数在栈中的位置肯定能知道,只要不定的参数个数能够根据
    第一个后者后续的明确的参数确定下来,就可以使用不定参数,例如对于CRT中的sprin
    tf函数,定义为:

    int sprintf(char* buffer,const char* format,...)

    由于所有的不定参数都可以通过format确定,因此使用不定个数的参数是没有问题的。

    fastcall
    fastcall调用约定和stdcall类似,它意味着:

    函数的第一个和第二个DWORD参数(或者尺寸更小的)通过ecx和edx传递,其他参数通过
    从右向左的顺序压栈
    被调用函数清理堆栈
    函数名修改规则同stdcall
    其声明语法为:int fastcall function(int a,int b)

    thiscall
    thiscall是唯一一个不能明确指明的函数修饰,因为thiscall不是关键字。它是C++类成
    员函数缺省的调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理,th
    iscall意味着:

    参数从右向左入栈
    如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针
    在所有参数压栈后被压入堆栈。
    对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈
    为了说明这个调用约定,定义如下类和使用代码:

    class A
    {
    public:
    int function1(int a,int b);
    int function2(int a,...);
    };
    int A::function1 (int a,int b)
    {
    return a+b;
    }
    #include
    int A::function2(int a,...)
    {
    va_list ap;
    va_start(ap,a);
    int i;
    int result = 0;
    for(i = 0 i < a i ++)
    {
    result += va_arg(ap,int);
    }
    return result;
    }
    void callee()
    {
    A a;
    a.function1 (1,2);
    a.function2(3,1,2,3);
    }

    callee函数被翻译成汇编后就变成:


    //函数function1调用
    0401C1D push 2
    00401C1F push 1
    00401C21 lea ecx,[ebp-8]
    00401C24 call function1 注意,这里this没有被入栈
    //函数function2调用
    00401C29 push 3
    00401C2B push 2
    00401C2D push 1
    00401C2F push 3
    00401C31 lea eax,[ebp-8] 这里引入this指针
    00401C34 push eax
    00401C35 call function2
    00401C3A add esp,14h

    可见,对于参数个数固定情况下,它类似于stdcall,不定时则类似cdecl

    naked call
    这是一个很少见的调用约定,一般程序设计者建议不要使用。编译器不会给这种函数增
    加初始化和清理代码,更特殊的是,你不能用return返回返回值,只能用插入汇编返回
    结果。这一般用于实模式驱动程序设计,假设定义一个求和的加法程序,可以定义为:


    __declspec(naked) int add(int a,int b)
    {
    __asm mov eax,a
    __asm add eax,b
    __asm ret
    }

    注意,这个函数没有显式的return返回值,返回通过修改eax寄存器实现,而且连退出函
    数的ret指令都必须显式插入。上面代码被翻译成汇编以后变成:


    mov eax,[ebp+8]
    add eax,[ebp+12]
    ret 8


    注意这个修饰是和__stdcall及cdecl结合使用的,前面是它和cdecl结合使用的代码,对
    于和stdcall结合的代码,则变成:

    __declspec(naked) int __stdcall function(int a,int b)
    {
    __asm mov eax,a
    __asm add eax,b
    __asm ret 8 //注意后面的8
    }

    至于这种函数被调用,则和普通的cdecl及stdcall调用函数一致。

    函数调用约定导致的常见问题
    如果定义的约定和使用的约定不一致,则将导致堆栈被破坏,导致严重问题,下面是两
    种常见的问题:

    函数原型声明和函数体定义不一致
    DLL导入函数时声明了不同的函数约定
    以后者为例,假设我们在dll种声明了一种函数为:

    __declspec(dllexport) int func(int a,int b);//注意,这里没有stdcall,使用的是
    cdecl
    使用时代码为:

    typedef int (*WINAPI DLLFUNC)func(int a,int b);
    hLib = LoadLibrary(...);
    DLLFUNC func = (DLLFUNC)GetProcAddress(...)//这里修改了调用约定
    result = func(1,2);//导致错误

    由于调用者没有理解WINAPI的含义错误的增加了这个修饰,上述代码必然导致堆栈被破
    坏,MFC在编译时插入的checkesp函数将告诉你,堆栈被破坏了。
    April 04

    什么是词法分析和语法分析

    词法分析(Lexical analysis或Scanning)和词法分析程序(Lexical analyzer或Scanner)
      词法分析阶段是编译过程的第一个阶段。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。词法分析程序实现这个任务。词法分析程序可以使用lex等工具自动生成。

    语法分析(Syntax analysis或Parsing)和语法分析程序(Parser)
      语法分析是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确.源程序的结构由上下文无关文法描述.

    语义分析(Syntax analysis)
      语义分析是编译过程的一个逻辑阶段. 语义分析的任务是对结构上正确的源程序进行上下文有关性质的审查, 进行类型审查.例如一个C程序片断:
      int arr[2],b;
      b = arr * 10;
      源程序的结构是正确的.
      语义分析将审查类型并报告错误:不能在表达式中使用一个数组变量,赋值语句的右端和左端的类型不匹配.

    Lex
      一个词法分析程序的自动生成工具。它输入描述构词规则的一系列正规式,然后构建有穷自动机和这个有穷自动机的一个驱动程序,进而生成一个词法分析程序.

    Yacc
      一个语法分析程序的自动生成工具。它接受语言的文法,构造一个LALR(1)分析程序.因为它采用语法制导翻译的思想,还可以接受用C语言描述的语义动作,从而构造一个编译程序. Yacc 是 Yet another compiler compiler的缩写.

    源语言(Source language)和源程序(Source program)
      被编译程序翻译的程序称为源程序,书写该程序的语言称为源语言.

    目标语言(Object language or Target language)和目标程序(Object program or Target program)
      编译程序翻译源程序而得到的结果程序称为目标程序, 书写该程序的语言称为目标语言.

    中间语言(中间表示)(Intermediate language(representation))
      在进行了语法分析和语义分析阶段的工作之后,有的编译程序将源程序变成一种内部表示形式,这种内部表示形式叫做中间语言或中间表示或中间代码。所谓“中间代码”是一种结构简单、含义明确的记号系统,这种记号系统复杂性介于源程序语言和机器语言之间,容易将它翻译成目标代码。另外,还可以在中间代码一级进行与机器无关的优化。

     

    文法(Grammars)
      文法是用于描述语言的语法结构的形式规则。文法G定义为四元组(,,,)。其中为非终结符号(或语法实体,或变量)集;为终结符号集;为产生式(也称规则)的集合;产生式(规则)是形如或 a ::=b 的(a , b)有序对,其中(∪)且至少含有一个非终结符,而(∪)。,和是非空有穷集。称作识别符号或开始符号,它是一个非终结符,至少要在一条规则中作为左部出现。
      一个文法的例子: G=(={A,R},={0,1} ,={A?0R,A?01,R?A1},=A)
    文法分类(A hierarchy of Grammars)
      著名语言学家Noam Chomsky定义了四类文法和四种形式语言类,文法的四种类型分别是0型、1型、2型和3型。几类文法的差别在于对产生式施加不同的限制,分别是:
      0型文法(短语结构文法)(phrase structure grammars):
      设G=(,,,),如果它的每个产生式是这样一种结构: (∪)  且至少含有一个非终结符,而(∪),则G是一个0型文法。
      1型文法(上下文有关文法)(context-sensitive grammars):
      设G=(,,,)为一文法,若中的每一个产生式均满足|,仅仅  除外,则文法G是1型或上下文有关的。
      2型文法(上下文无关文法)(context-free grammars):
      设G=(,,,),若P中的每一个产生式满足:是一非终结符,(∪)  则此文法称为2型的或上下文无关的。
      3型文法(正规文法)(regular grammars):
      设G=(,,,),若中的每一个产生式的形式都是A→aB或A→a,其中A和B都是非终结,a是终结符,则G是3型文法或正规文法。
      0型文法产生的语言称为0型语言。
      1型文法产生的语言称为1型语言,也称作上下文有关语言。
      2型文法产生的语言称为2型语言,也称作上下文无关语言。
      3型文法产生的语言称为3型语言,也称作正规语言。

    内聚和耦合

    内聚(Cohesion)是一个模块内部各成分之间相关联程度的度量。耦合(Coupling)是模块之间依赖程度的度量。内聚和耦合是密切相关的,与其它模块存在强耦合的模块通常意味着弱内聚,而强内聚的模块通常意味着与其它模块之间存在弱耦合。模块设计追求强内聚,弱耦合。  
    一、内聚强度  
    内聚按强度从低到高有以下几种类型:  
    (1)偶然内聚。如果一个模块的各成分之间毫无关系,则称为偶然内聚。  
    (2)逻辑内聚。几个逻辑上相关的功能被放在同一模块中,则称为逻辑内聚。如一个模块读取各种不同类型外设的输入。尽管逻辑内聚比偶然内聚合理一些,但逻辑内聚的模块各成分在功能上并无关系,即使局部功能的修改有时也会影响全局,因此这类模块的修改也比较困难。  
    (3)时间内聚。如果一个模块完成的功能必须在同一时间内执行(如系统初始化),但这些功能只是因为时间因素关联在一起,则称为时间内聚。  
    (4)过程内聚。如果一个模块内部的处理成分是相关的,而且这些处理必须以特定的次序执行,则称为过程内聚。  
    (5)通信内聚。如果一个模块的所有成分都操作同一数据集或生成同一数据集,则称为通信内聚。  
    (6)顺序内聚。如果一个模块的各个成分和同一个功能密切相关,而且一个成分的输出作为另一个成分的输入,则称为顺序内聚。  
    (7)功能内聚。模块的所有成分对于完成单一的功能都是必须的,则称为功能内聚。  
    二、耦合强度  
    耦合的强度依赖于以下几个因素:(1)一个模块对另一个模块的调用;(2)一个模块向另一个模块传递的数据量;(3)一个模块施加到另一个模块的控制的多少;(4)模块之间接口的复杂程度。  
    耦合按从强到弱的顺序可分为以下几种类型:  
    (1)内容耦合。当一个模块直接修改或操作另一个模块的数据,或者直接转入另一个模块时,就发生了内容耦合。此时,被修改的模块完全依赖于修改它的模块。  
    (2)公共耦合。两个以上的模块共同引用一个全局数据项就称为公共耦合。  
    (3)控制耦合。一个模块在界面上传递一个信号(如开关值、标志量等)控制另一个模块,接收信号的模块的动作根据信号值进行调整,称为控制耦合。  
    (4)标记耦合。模块间通过参数传递复杂的内部数据结构,称为标记耦合。此数据结构的变化将使相关的模块发生变化。  
    (5)数据耦合。模块间通过参数传递基本类型的数据,称为数据耦合。  
    (6)非直接耦合。模块间没有信息传递时,属于非直接耦合。  
    如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,坚决避免使用内容耦合。
    April 03

    一个完整开发环境应该具有的几个系统

    1. unit test system, to build unit test. For example: Embeded unit
    2. trace system: to print trace information while debugging
    3. build system: like "make file", allows you building different version, such as debug vision, standard distribution version, special platform version, partial function version etc.
    4. common lib. Some very useful functions like advanced string functions, basic data structure like dynamic array, link list, stack, queue etc. If those functions are not available in you system, for example, basic c system, you should build one yourself.
    5. bug trace system: to trace your bug. Bugzilla & Bugfree
    6. source control system: CVS(free) Perforce
    7. ...more, any comments are welcome
    March 06

    bin-search

    /*
     * Perform a binary search.
     *
     * The code below is a bit sneaky.  After a comparison fails, we
     * divide the work in half by moving either left or right. If lim
     * is odd, moving left simply involves halving lim: e.g., when lim
     * is 5 we look at item 2, so we change lim to 2 so that we will
     * look at items 0 & 1.  If lim is even, the same applies.  If lim
     * is odd, moving right again involes halving lim, this time moving
     * the base up one item past p: e.g., when lim is 5 we change base
     * to item 3 and make lim 2 so that we will look at items 3 and 4.
     * If lim is even, however, we have to shrink it by one before
     * halving: e.g., when lim is 4, we still looked at item 2, so we
     * have to make lim 3, then halve, obtaining 1, so that we will only
     * look at item 3.
     */
    void *
    bsearch(key, base0, nmemb, size, compar)
     const void *key;
     const void *base0;
     size_t nmemb;
     size_t size;
     int (*compar)(const void *, const void *);
    {
     const char *base = base0;
     size_t lim;
     int cmp;
     const void *p;
     for (lim = nmemb; lim != 0; lim >>= 1) {
      p = base + (lim >> 1) * size;
      cmp = (*compar)(key, p);
      if (cmp == 0)
       return ((void *)p);
      if (cmp > 0) { /* key > p: move right */
       base = (char *)p + size;
       lim--;
      }  /* else move left */
     }
     return (NULL);
    }
    December 01

    据说是Google的面试题目

    在常数e里找出第一个10位的质数(find the first ten-digit prime number in the mathematical constant called 'e')。
     
    Thinking about this.
    November 30

    编程规范

    不知道是哪个公司的编程规范,有些规定不错,有些不太赞成,有些不理解含义,放到这里做个参考。
     
    基本要求

    1.1 程序结构清析,简单易懂,单个函数的程序行数不得超过100行。
    1.2 打算干什么,要简单,直接了当,代码精简,避免垃圾程序。
    1.3 尽量使用标准库函数和公共函数。
    1.4 不要随意定义全局变量,尽量使用局部变量。
    1.5 使用括号以避免二义性。

    2.可读性要求
    2.1 可读性第一,效率第二。
    2.2 保持注释与代码完全一致。
    2.3 每个源程序文件,都有文件头说明,说明规格见规范。
    2.4 每个函数,都有函数头说明,说明规格见规范。
    2.5 主要变量(结构、联合、类或对象)定义或引用时,注释能反映其含义。
    2.7 常量定义(DEFINE)有相应说明。
    2.8 处理过程的每个阶段都有相关注释说明。
    2.9 在典型算法前都有注释。
    2.10 利用缩进来显示程序的逻辑结构,缩进量一致并以Tab键为单位,定义Tab为 6个字节。
    2.11 循环、分支层次不要超过五层。
    2.12 注释可以与语句在同一行,也可以在上行。
    2.13 空行和空白字符也是一种特殊注释。
    2.14 一目了然的语句不加注释。
    2.15 注释的作用范围可以为:定义、引用、条件分支以及一段代码。
    2.16 注释行数(不包括程序头和函数头说明部份)应占总行数的 1/5 到 1/3 。


    3. 结构化要求

    3.1 禁止出现两条等价的支路。
    3.2 禁止GOTO语句。
    3.3 用 IF 语句来强调只执行两组语句中的一组。禁止 ELSE GOTO 和 ELSE RETURN。
    3.4 用 CASE 实现多路分支。
    3.5 避免从循环引出多个出口。
    3.6 函数只有一个出口。
    3.7 不使用条件赋值语句。
    3.8 避免不必要的分支。
    3.9 不要轻易用条件分支去替换逻辑表达式。

    4. 正确性与容错性要求

    4.1 程序首先是正确,其次是优美
    4.2 无法证明你的程序没有错误,因此在编写完一段程序后,应先回头检查。
    4.3 改一个错误时可能产生新的错误,因此在修改前首先考虑对其它程序的影响。
    4.4 所有变量在调用前必须被初始化。
    4.5 对所有的用户输入,必须进行合法性检查。
    4.6 不要比较浮点数的相等,
    如: 10.0 * 0.1 == 1.0 , 不可靠
    4.7 程序与环境或状态发生关系时,必须主动去处理发生的意外事件,如文件能否逻辑锁定、打印机是否联机等。
    4.8 单元测试也是编程的一部份,提交联调测试的程序必须通过单元测试。

    5. 可重用性要求

    5.1 重复使用的完成相对独立功能的算法或代码应抽象为公共控件或类。
    5.2 公共控件或类应考虑OO思想,减少外界联系,考虑独立性或封装性。
    5.3 公共控件或类应建立使用模板。

    附:C++ 编程规范,delphi作相应的参考


    .1适用范围

    本标准适用于利用Visul C++ ,Borland C++进行软件程序开发的人员.。



    .2变量命名

    命名必须具有一定的实际意义,形式为xAbcFgh,x由变量类型确定,Abc、Fgh表示连续意义字符串,如果连续意义字符串仅两个,可都大写.如OK.

    具体例程:

    BOOL类型 bEnable;

    ch * char chText
    c * 类对象 cMain(对象实例)
    h * Handle(句柄) hWnd
    i * int
    n * 无符号整型
    p * 指针
    sz,str * 字符串
    w WORD
    x,y 坐标

    Char或者TCHAR类型 与Windows API有直接联系的用szAppName[10]形式否则用FileName[10]形式,单个字符也可用小写字母表示;

    Int类型 nCmdShow;
    LONG类型 lParam;
    UINT类型 uNotify;
    DWORD类型 dwStart;
    PSTR类型 pszTip;
    LPSTR类型 lpCmdLine
    LPTSTR类型 lpszClassName;
    LPVOID类型 lpReserved
    WPARAM类型 wParam,
    LPARAM类型 lParam
    HWND类型 hDlg;
    HDC类型 hDC;
    HINSTANCE类型 hInstance
    HANDLE类型 hInstance,
    HICON类型 hIcon;
    int iTmp
    float fTmp
    DWORD dw*
    String , AnsiString str *
    m_ 类成员变量 m_nVal, m_bFlag
    g_ 全局变量 g_nMsg, g_bFlag

    局部变量中可采用如下几个通用变量:nTemp,nResult,I,J(一般用于循环变量)。

    其他资源句柄同上

    .3常量命名和宏定义

    常量和宏定义必须具有一定的实际意义;
    常量和宏定义在#include和函数定义之间;
    常量和宏定义必须全部以大写字母来撰写,中间可根据意义的连续性用下划线连接,每一条定义的右侧必须有一简单的注释,说明其作用;
    资源名字定义格式:

    菜单:IDM_XX或者CM_XX
    位图:IDB_XX
    对话框:IDD_XX
    字符串:IDS_XX
    DLGINIT:DIALOG_XX
    ICON:IDR_XX

    .4函数命名

    函数原型说明包括引用外来函数及内部函数,外部引用必须在右侧注明函数来源: 模块名及文件名, 如是内部函数,只要注释其定义文件名;

    第一个字母必须使用大写字母,要求用大小写字母组合规范函数命名,必要时可用下划线间隔,示例如下:

    void UpdateDB_Tfgd (TRACK_NAME); //Module Name :r01/sdw.c
    void PrintTrackData (TRACK_NAME); //Module Name :r04/tern.c
    void ImportantPoint (void); //Module Name :r01/sdw.c
    void ShowChar (int , int , chtype); //Local Module
    void ScrollUp_V (int , int); //Local Module

    .5结构体命名

    结构体类型命名必须全部用大写字母,原则上前面以下划线开始;结构体变量命名必须用大小写字母组合,第一个字母必须使用大写字母,必要时可用下划线间隔。对于私有数据区,必须注明其所属的进程。全局数据定义只需注意其用途。

    示例如下:

    typedef struct
    {
        char szProductName[20];
        char szAuthor[20];
        char szReleaseDate[16];
        char szVersion[10];
        unsigned long MaxTables;
        unsigned long UsedTables;
    }DBS_DATABASE;

    DBS_DATABASE GdataBase;

    6 控件的命名:
    用小写前缀表示类别:
    fm 窗口
    cmd 按钮
    cob combo,下拉式列表框
    txt 文本输入框
    lab labal,标签
    img image,图象
    pic picture
    grd Grid,网格
    scr 滚动条
    lst 列表框
    frm fram

    7注释

    原则上注释要求使用中文;

    文件开始注释内容包括:公司名称、版权、作者名称、时间、模块用途、背景介绍等,复杂的算法需要加上流程说明;
    函数注释包括:输入、输出、函数描述、流程处理、全局变量、调用样例等,复杂的函数需要加上变量用途说明;
    程序中注释包括:修改时间和作者、方便理解的注释等;

    引用一: 文件开头的注释模板

    /******************************************************************
    ** 文件名:
    ** Copyright (c) 1998-1999 *********公司技术开发部
    ** 创建人:
    ** 日 期:
    ** 修改人:
    ** 日 期:
    ** 描 述:
    **
    ** 版 本:
    **-----------------------------------------------------------------------------
    ******************************************************************/

    引用二: 函数开头的注释模板
    /*****************************************************************
    ** 函数名:
    ** 输 入: a,b,c
    ** a---
    ** b---
    ** c---
    ** 输 出: x---
    ** x 为 1, 表示...
    ** x 为 0, 表示...
    ** 功能描述:
    ** 全局变量:
    ** 调用模块:
    ** 作 者:
    ** 日 期:
    ** 修 改:
    ** 日 期:
    ** 版本
    ****************************************************************/

    引用三: 程序中的注释模板
    /*----------------------------------------------------------*/
    /* 注释内容 */
    /*----------------------------------------------------------*/

    8 程序

    a. 程序编码力求简洁,结构清晰,避免太多的分支结构及太过于技巧性的程序,尽量不采用递归模式。
    b. 编写程序时,亦必须想好测试的方法,换句话说,”单元测试” 的测试方案应在程序编写时一并拟好。
    c. 注释一定要与程序一致。
    d. 版本封存以后的修改一定要将老语句用/* */ 封闭,不能自行删除或修改,并要在文件及函数的修改记录中加以记录。
    e. 程序中每个block 的开头 ”{" 及 "}” 必须对齐,嵌套的block 每进一套,缩进一个tab,TAB 为4个空格,block类型包括if、for、while、do等关键字引出的。
    f. 对于比较大的函数,每个block 和特殊的函数调用,都必须注明其功能,举例如下:

    count.divisor = 1193280 / freq; // compute the proper count
    OutByte((unsigned short)67, (unsigned char)182); // tell 8253 that acount is coming
    OutByte((unsigned short)66, count. c[0]); // send low-order byte
    OutByte((unsigned short)66, count. c[1]); // send high-order byte
    ×××××××××××××××××××××××××××××××××××××××

    bcb,delphi中的变量命名:

    遵循匈牙利命名法,命名必须有意义,制定如下规定

    窗体: 以大写的W开始,如About版权窗体, 命名为WAbout
    文件:以大写的F开始,如About版权窗体,文件命名为FAbout.cpp
    按钮(Button):如退出按钮,命名为btnExit
    ……
    基类: 加base标记,如报表基类,窗体命名为:WBaseRep, 文件命名为FBaseRep.cpp