fengyu_1907
驱动牛犊
驱动牛犊
  • 注册日期2003-04-16
  • 最后登录2008-06-05
  • 粉丝0
  • 关注0
  • 积分137分
  • 威望15点
  • 贡献值0点
  • 好评度13点
  • 原创分0分
  • 专家分0分
阅读:1364回复:0

老生常谈:提高程序质量的注意事项

楼主#
更多 发布于:2008-05-12 19:00

Author: brike.huang
Email: brike.huang@163.com
QQ: 24558102
Date: 2008.05
--------------------
以下是我从事windows开发的一些心得,希望对各位有所帮助


软件开发,比较重要是软件需求、进度控制、质量管理等,本主题主要讨论质量——程序的质量

程序的质量,主要表现在以下几方面:
1稳定性
2可移植性
3兼容性
4可维护性
.......


=================
1.使用中性的数据类型,避免使用绝对数据类型(除非有需求)
    在程序中尽量使用INT,TCHAR,LPTCSTR,DWORD等类型,如果是指针,可以使用VOID,PVOID或DWORD_PTR、ULONG_PTR、UINT_PTR类型在UNICODE环境下,TCHAR定义为unsigned short,在ASCII环境下定义为char类型......
    在64位环境下,PVOID、XXXX_PTR等类型长度为8Bytes,在32位环境下,为4Bytes。xxxx_PTR数据类型需要SDK支持,该类型对64位服务器版本的程序影响比较大,程序有可能会使用到大于4G的地址空间

2.使用中性的函数
    很多函数有多种形态,最常见的是UNICODE与ASCII,64位与32位。
    如:_tcslen,UNICODE环境下定义为wcslen(用于处理UNICODE字符串长度),ASCII环境下定义为strlen(用于处理ASCII字符串长度)
    使用GetWindowLongPtr代替GetWindowLong,有很多类似的API,具体请参考SDK

3.使用UNICODE编译环境
    windows2000及以后的系统,已经是纯UNICODE环境了。ASCII环境下处理亚洲文字时,容易出现乱码。
    具体方法:在编译条件中加入_UNICODE、UNICODE符号定义,在链接时指定程序入口
        windows程序入口:wWinMainCRTStartup
        console程序入口:wMainCRTStartup
        dll程序入口:wDllMainCRTStartup
    在程序中,有可能必须使用ASCII(比如与COM通讯),程序中应该增加相应处理:
#ifdef UNICODE
...
#else
...
#endif

4.使用安全的字符处理方法
    使用strsafe.h中的函数,而不是默认的
    如StringCbCopy代替_tcscpy(ASCII对应strcpy),StringCbCat代替代_tcscat(ASCII对应strcat)。能有效的防止内存溢出

5.初始化变量

    比如,定义了TCHAR szBuffer[254],然后通过一个API取得一个字串。但该API调用失败,此时反应到UI上是一串乱七八糟的东西,更严重的后果是导致程序运行崩溃。
    一般把变量全部初始化0,如:TCHAR szBuffer[254] = {0};

6.条件运算时,常数或不能改变的变量作为第一目运算符
    如经常犯的错误: if (n == 3) ...错写成
        if (3 = n) ....
    编译时直接给出错误信息
    如果写成
        if (n = 3),在成千上万的代码中,要找到它,会让人发狂

7.注意API版本的说明
    有部分API在新版本的OS中才支持,如果程序要在旧版本的OS运行,因在DLL中找不到链接符号,而终止运行
    比如:SetupDiCreateDeviceInfoListEx,SDK中的相关描述如下:
        Client: Requires Windows XP or Windows 2000 Professional.
        Server: Requires Windows Server 2003 or Windows 2000 Server.
    如果程序是隐性链接并对应的Setupapi.dll没附带进安装路径,程序在windows2000以下版本上将不能运行

8.在程序中使用调试用语
    如_RPTF0、_RPTF1、.....可以在VC的Output窗口或DbgView之类型的工具查看程序运行状态,在容易出生错误的地方使用assert之类的用语,在程序崩溃时会告诉开发人员哪行代码出现问题

9.分配的内存一定要初始化,并说明在什么条件下使用什么函数释放(free?delete?HeapFree?.....)
    一般情况下初始化为0,理由与第5条“初始化变量”相同。
    如果是小型程序,并申请的内存不多,很多人偷懒不做这个烦人的动作。我有一擅长VB与.net的同事,做图形处理,程序处理不到几张图片,就消耗掉所有内存,最先想到的办法就是买内存条,结果只是增加了几张图片的吞吐量,后来采取关程序,再开程序的方法运行。一个小组七八人花了一个多月都找不到问题。最后在我拜访他们部门时,花了不到半小时就解决了。

10.提升编译警告级别
    如果使用VC6,默认为/W3,SDK默认为/W4。SDK在编译时就能发现更多隐性问题。
---------------------
以上几个规则都是很容易做到的,我个人比较喜欢使用UNICODE、64BIT的AMD编译链接SDK环境,在这个环境下写程序,一般不会遇到兼容或移植上的问题,代码不用做多大的变化,就可以应用到WINDOWS各个版本上,只需要在不同的编译条件下重新Rebuild。

以下提供一个SAMPLE:

#include <windows.h>
#include <tchar.h>
#include <crtdbg.h>
#include <strsafe.h>
#define OPTIONAL_LEN    10

#ifdef _DEBUG
#define DEBUG_PRINT1(IF, msg, arg1)    if (!(IF)) _RPTF1(_CRT_WARN, msg, arg1)
#else
#define DEBUG_PRINT1        // Release版本该语句为空
#endif

INT _tmain(INT argc, TCHAR* argv[])
{
    TCHAR szOptional[3][OPTIONAL_LEN] = {0};
    
    DEBUG_PRINT1(3 <= argc, ("arg number: %d\n"), argc);    // 如果参数数量小于3,则输出调试信息 [5/12/2008]

    if (3 > argc) return -1;

    for (INT n = 0; 3 > n; ++n)
    {
        StringCbCopy(szOptional[n], sizeof(TCHAR) * OPTIONAL_LEN, __argv[n]);    // 保存参数的长度不超过

OPTIONAL_LEN个字符 [5/12/2008]
        _tprintf(_T("arg%d: %s\n"), n, szOptional[n]);
    }
    return 0;
}

---------------
以上程序兼容UNICODE、防止内存溢出

最新喜欢:

linshierlinshi...
游客

返回顶部