• 读华为规范文档的心得体会



    转于http://blog.csdn.net/app_12062011/article/details/9156757
    内容简介:写函数参数的注意,调试的心得体会

    1.关于函数使用:

    1.1 接口函数参数

    在同一项目组应明确规定对接口函数参数的合法性检查应由函数的调用者负责还是由接口函数本身负责,缺省是由函数调用者负责。

    说明:对于模块间接口函数的参数的合法性检查这一问题,往往有两个极端现象,即:要么是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这一必要的处理过程,造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查,这种情况虽不会造成问题,但产生了冗余代码,降低了效率。

    1.2  非调度函数应减少或防止控制参数,尽量只使用数据参数。

    说明:本建议目的是防止函数间的控制耦合。调度函数是指根据输入的消息类型或控制命令,来启动相应的功能实体(即函数或过程),而本身并不完成具体功能。控制参数是指改变函数功能行为的参数,即函数要根据此参数来决定具体怎样工作。非调度函数的控制参数增加了函数间的控制耦合,很可能使函数间的耦合度增大,并使函数的功能不唯一。

    示例:如下函数构造不太合理。
    int add_sub( int a, int b, unsigned char add_sub_flg )
    {
        if (add_sub_flg == INTEGER_ADD)
        {
            return (a + b);
        }
        else
        {
            return (a - b);

        }

    }

    不如分为如下两个函数清晰。

    int add( int a, int b )

    {

        return (a + b);

    }

    int sub( int a, int b ) 
    {
        return (a - b);

    }

    1.3  除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换方式作为返回值返回。

    1.4  在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换。

    1.5  设计高扇入、合理扇出(小于7)的函数。

    说明:扇出是指一个函数直接调用(控制)其它函数的数目,而扇入是指有多少上级函数调用它。

    扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,如总是1,表明函数的调用层次可能过多,这样不利程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。函数较合理的扇出(调度函数除外)通常是3-5。扇出太大,一般是由于缺乏中间层次,可适当增加中间层次的函数。扇出太小,可把下级函数进一步分解多个函数,或合并到上级函数中。当然分解或合并函数时,不能改变要实现的功能,也不能违背函数间的独立性。

    扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间的独立性而单纯地追求高扇入。公共模块中的函数及底层函数应该有较高的扇入。

    较良好的软件结构通常是顶层函数的扇出较高,中层函数的扇出较少,而底层函数则扇入到公共模块中。

    1.6 避免使用BOOL参数。

    说明:原因有二,其一是BOOL参数值无意义,TURE/FALSE的含义是非常模糊的,在调用时很难知道该参数到底传达的是什么意思;其二是BOOL参数值不利于扩充。还有NULL也是一个无意义的单词。

    1.7 对于提供了返回值的函数,在引用时最好使用其返回值。

    1.8  当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替。 

    说明:这样可以增加编程效率和程序的可读性。

    示例:在某过程中较多引用TheReceiveBuffer[FirstSocket].byDataPtr,

    则可以通过以下宏定义来代替:

    # define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr

    2.关于可测性

    2.1 打印信息

    在同一项目组或产品组内,调测打印出的信息串的格式要有统一的形式。信息串中至少要有所在模块名(或源文件名)及行号。

    说明:统一的调测信息格式便于集成测试。

     2.2 断言使用

    2.2.1 使用断言来发现软件问题,提高代码可测性。

    说明:断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。

    示例:下面是C语言中的一个断言,用宏来设计的。(其中NULL为0L)

    #ifdef _EXAM_ASSERT_TEST_  // 若使用断言测试

    void exam_assert( char * file_name, unsigned int line_no )

    {

        printf( " [EXAM]Assert failed: %s, line %u ", 

                file_name, line_no );

        abort( );

    }

    #define  EXAM_ASSERT( condition )

        if (condition) // 若条件成立,则无动作

            NULL;

        else  // 否则报告

            exam_assert( __FILE__, __LINE__ ) 

    #else  // 若不使用断言测试

    #define EXAM_ASSERT(condition)  NULL 

    #endif  /* end of ASSERT */

    2.2.2 断言检查程序正常运行时不应该发生但调试时有可能发生的非法情况,它和出错处理是不同的。

    2.2.3 要用断言确认函数参数,保证没有定义的特性或者功能不被使用。例如:假设某通信模块在设计时,准备提供“无连接”和“连接” 这两种业务。但当前的版本中仅实现了“无连接”业务,且在此版本的正式发行版中,用户(上层模块)不应产生“连接”业务的请求,那么在测试时可用断言检查用户是否使用“连接”业务。如下。

    #define EXAM_CONNECTIONLESS 0 // 无连接业务

    #define EXAM_CONNECTION     1 // 连接业务

    int msg_process( EXAM_MESSAGE *msg )

    {

        unsigned char service; /* message service class */

        EXAM_ASSERT( msg != NULL );

    service = get_msg_service_class( msg );

        EXAM_ASSERT( service != EXAM_CONNECTION ); // 假设不使用连接业务

        ...  //other program code

    }

    2.2.4 断言还可以检查程序开发环境(OS/Compiler/Hardware)

    说明:程序运行时所需的软硬件环境及配置要求,不能用断言来检查,而必须由一段专门代码处理。用断言仅可对程序开发环境中的假设及所配置的某版本软硬件是否具有某种功能的假设进行检查。如某网卡是否在系统运行环境中配置了,应由程序中正式代码来检查;而此网卡是否具有某设想的功能,则可由断言来检查。

    对编译器提供的功能及特性假设可用断言检查,原因是软件最终产品(即运行代码或机器码)与编译器已没有任何直接关系,即软件运行过程中(注意不是编译过程中)不会也不应该对编译器的功能提出任何需求。

    示例:用断言检查编译器的int型数据占用的内存空间是否为2,如下。

    EXAM_ASSERT( sizeof( int ) == 2 );

    2.2.5 正式软件中,应该断掉调测开关。不要同时存在正式版本和debug版本的源文件

    2.3 编写防错程序,然后在处理错误之后可用断言宣布发生错误。

    示例:假如某模块收到通信链路上的消息,则应对消息的合法性进行检查,若消息类别不是通信协议中规定的,则应进行出错处理,之后可用断言报告,如下例。

    #ifdef _EXAM_ASSERT_TEST_ // 若使用断言测试

    /* Notice: this function does not call 'abort' to exit program */

    void assert_report( char * file_name, unsigned int line_no )

    {

        printf( " [EXAM]Error Report: %s, line %u ", 

                file_name, line_no );

    }

    #define  ASSERT_REPORT( condition ) 

        if ( condition ) // 若条件成立,则无动作

            NULL;

        else // 否则报告

            assert_report ( __FILE__, __LINE__ ) 

    #else // 若不使用断言测试

    #define ASSERT_REPORT( condition )  NULL 

    #endif /* end of ASSERT */

    int msg_handle( unsigned char msg_name, unsigned char * msg )

    {

        switch( msg_name )

        {

            case MSG_ONE:

                ... // 消息MSG_ONE处理

                return MSG_HANDLE_SUCCESS;

        

                ... // 其它合法消息处理

        

            default:

                ... // 消息出错处理

                ASSERT_REPORT( FALSE );  // “合法”消息不成立,报告

                return MSG_HANDLE_ERROR;

        }

    }

     3. 关于效率

    #define PAI_RECIPROCAL (1 / 3.1416 ) // 编译器编译时,将生成具体浮点数

    4.代码测试、维护

    4.1 单元测试要求至少达到语句覆盖

    4.2 单元测试开始要跟踪每一条语句,并观察数据流及变量的变化

    4.3 清理、整理或优化后的代码要经过审查及测试。

    4.4 代码版本升级要经过严格测试

    4.5 使用工具软件对代码版本进行维护

    4.6 正式版本上软件的任何修改都应有详细的文档记录

    4.7  其他

    4.7.1  发现错误立即修改,并且要记录下来。

    4.7.2  关键的代码在汇编级跟踪。

    4.7.3  仔细设计并分析测试用例,使测试用例覆盖尽可能多的情况,以提高测试用例的效率。

    4.7.4  尽可能模拟出程序的各种出错情况,对出错处理代码进行充分的测试。

    4.7.5  仔细测试代码处理数据、变量的边界情况。

    4.7.6  保留测试信息,以便分析、总结经验及进行更充分的测试。

    4.7.7  不应通过“试”来解决问题,应寻找问题的根本原因。

    4.7.8  对自动消失的错误进行分析,搞清楚错误是如何消失的。

    4.7.9  修改错误不仅要治表,更要治本。

    4.7.10 测试时应设法使很少发生的事件经常发生。

    4.7.11 明确模块或函数处理哪些事件,并使它们经常发生。

    4.7.12 坚持在编码阶段就对代码进行彻底的单元测试,不要等以后的测试工作来发现问题。

    4.7.13 去除代码运行的随机性(如去掉无用的数据、代码及尽可能防止并注意函数中的“内部寄存器”等),让函数运行的结果可预测,并使出现的错误可再现。

    5 使用代码检查工具(如C语言用PC-Lint)对源程序检查。

    6 使用软件工具(如 LogiSCOPE)进行代码审查

     
  • 相关阅读:
    memcached在大负载高并发网站上的应用(转)
    NHibernate in Action(序,前言,致谢)
    php 数据类型
    w3wp 备忘录
    EF实例化Context
    爬虫程序判断是否已抓URL
    NHibenate in Action(目录)
    C#中静态构造函数的学习
    webservice 无法在网页中进行测试问题
    汉诺塔问题C#
  • 原文地址:https://www.cnblogs.com/mingyoujizao/p/8575566.html
Copyright © 2020-2023  润新知