c程序开发让你的代码足够的强大

上传人:第*** 文档编号:32876345 上传时间:2018-02-12 格式:DOC 页数:12 大小:103.50KB
返回 下载 相关 举报
c程序开发让你的代码足够的强大_第1页
第1页 / 共12页
c程序开发让你的代码足够的强大_第2页
第2页 / 共12页
c程序开发让你的代码足够的强大_第3页
第3页 / 共12页
c程序开发让你的代码足够的强大_第4页
第4页 / 共12页
c程序开发让你的代码足够的强大_第5页
第5页 / 共12页
点击查看更多>>
资源描述

《c程序开发让你的代码足够的强大》由会员分享,可在线阅读,更多相关《c程序开发让你的代码足够的强大(12页珍藏版)》请在金锄头文库上搜索。

1、C+程序开发 让你的代码足够的强大!作者:xxxluozhen在实际的项目中,当项目的代码量不断增加的时候,你会发现越来越难管理和跟踪其各个组件,如其不善,很容易就引入 BUG。因此、我们应该掌握一些能让我们程序更加健壮的方法。这篇文章提出了一些建议,能有引导我们写出更加强壮的代码,以避免产生灾难性的错误。即使、因为其复杂性和项目团队结构,你的程序目前不遵循任何编码规则,按照下面列出的简单的规则可以帮助您避免大多数的崩溃情况。背景先来介绍下作者开发一些软件(CrashRpt),你可以http:/ CrashRpt 顾名思义软件崩溃记录软件(库),它能够自动提交你电脑上安装的软件错误记录。它通过

2、以太网直接将这些错误记录发送给你,这样方便你跟踪软件问题,并及时 修改,使得用户感觉到每次发布的软件都有很大的提高,这样他们自然很高兴。图 1、CrashRpt 库检测到错误弹出的对话框在分析接收的错误记录的时候,我们发现采用下文介绍的方法能够避免大部分程序崩溃的错误。例如、局部变量未初始化导致数组访问越界,指针使用前未进行检测(NULL)导致访问访问非法区域等。我已经总结了几条代码设计的方法和规则,在下文一一列出,希望能够帮助你避免犯一些错误,使得你的程序更加健壮。局部变量的初始化使用未初始化的局部变量是引起程序崩溃的一个比较普遍的原因,例如、来看下面这段程序片段:/ Define loca

3、l variablesBOOL bExitResult; / This will be TRUE if the function exits successfullyFILE* f; / Handle to fileTCHAR szBuffer_MAX_PATH; / String buffer / Do something with variables above. 上面的这段代码存在着一个潜在的错误,因为没有一个局部变量初始化了。当你的代码运行的时候,这些变量将被默认负一些错误的数值。例如 bExitResult 数值将被负为-135913245 ,szBuffer 必须以“0”结尾,结果

4、不会。因此、局部变量初始化时非常重要的,如下正确代码:/ Define local variables/ Initialize function exit code with FALSE to indicate failure assumptionBOOL bExitResult = FALSE; / This will be TRUE if the function exits successfully/ Initialize file handle with NULLFILE* f = NULL; / Handle to file/ Initialize string buffer wit

5、h empty stringTCHAR szBuffer_MAX_PATH = _T(); / String buffer/ Do something with variables above. 注意:有人说变量初始化会引起程序效率降低,是的,确实如此,如果你确实非常在乎程序的执行效率,去除局部变量初始化,你得想好其后果。初始化 WinAPI 结构许多 Windows API 都接受或则返回一些结构体参数,结构体如果没有正确的初始化,也很有可能引起程序崩溃。大家可能会想起用 ZeroMemory 宏或者 memset()函数去用 0 填充这个结构体(对结构体对应的元素设置默认值)。但是大部分

6、Windows API 结构体都必须有一个 cbSIze 参数,这个参数必须设置为这个结构体的大小。看看下面代码,如何初始化 Windows API 结构体参数:NOTIFYICONDATA nf; / WinAPI structurememset( / Zero memorynf.cbSize = sizeof(NOTIFYICONDATA); / Set structure size!/ Initialize other structure membersnf.hWnd = hWndParent;nf.uID = 0; nf.uFlags = NIF_ICON | NIF_TIP;nf.h

7、Icon = :LoadIcon(NULL, IDI_APPLICATION);_tcscpy_s(nf.szTip, 128, _T(Popup Tip Text);/ Add a tray iconShell_NotifyIcon(NIM_ADD, 注意:千万不要用 ZeroMemory 和 memset 去初始化那些包括结构体对象的结构体,这样很容易破坏其内部结构体,从而导致程序崩溃。/ Declare a C+ structurestruct ItemInfostd:string sItemName; / The structure has std:string object insi

8、deint nItemValue; / Init the structureItemInfo item;/ Do not use memset()! It can corrupt the structure/ memset(/ Instead use the followingitem.sItemName = item1;item.nItemValue = 0; 这里最好是用结构体的构造函数对其成员进行初始化./ Declare a C+ structurestruct ItemInfo/ Use structure constructor to set members with defaul

9、t valuesItemInfo()sItemName = _T(unknown);nItemValue = -1; std:string sItemName; / The structure has std:string object insideint nItemValue;/ Init the structureItemInfo item;/ Do not use memset()! It can corrupt the structure/ memset(/ Instead use the followingitem.sItemName = item1;item.nItemValue

10、= 0;验证功能的传入在函数设计的时候,对传入的参数进行检测是一直都推荐的。例如、如果你设计的函数是公共 API 的一部分,它可能被外部客户端调用,这样很难保证客户端传进入的参数就是正确的。例如,让我们来看看这个 hypotethical DrawVehicle() 函数,它可以根据不同的质量来绘制一辆跑车,这个质量数值(nDrawingQaulity )是0100。prcDraw 定义这辆跑车的轮廓区域。看看下面代码,注意观察我们是如何在使用函数参数之前进行参数检测:BOOL DrawVehicle(HWND hWnd, LPRECT prcDraw, int nDrawingQuality

11、)/ Check that window is validif(!IsWindow(hWnd)return FALSE;/ Check that drawing rect is validif(prcDraw=NULL)return FALSE;/ Check drawing quality is validif(nDrawingQuality100)return FALSE;/ Now its safe to draw the vehicle/ .return TRUE;指针的验证在指针使用之前,不检测是非常普遍的,这个可以说是我们引起软件崩溃最有可能的原因。如果你用一个指针,这个指针刚好是

12、 NULL,那么你的程序在运行时,将报出异常。CVehicle* pVehicle = GetCurrentVehicle();/ Validate pointerif(pVehicle=NULL)/ Invalid pointer, do not use it!return FALSE;如果你的函数创建了一个对象,并要将它作为函数的返回参数。那么记得在使用之前把他复制为 NULL。如不然,这个函数的调用者将使用这个无效的指针,进而一起程序错误。如下错误代码:int CreateVehicle(CVehicle* ppVehicle)if(CanCreateVehicle()*ppVehicl

13、e = new CVehicle();return 1; / If CanCreateVehicle() returns FALSE,/ the pointer to *ppVehcile would never be set!return 0;正确的代码如下;int CreateVehicle(CVehicle* ppVehicle)/ First initialize the output parameter with NULL*ppVehicle = NULL;if(CanCreateVehicle()*ppVehicle = new CVehicle();return 1; retur

14、n 0;清理已删除对象的指针在内存释放之后,无比将指针复制为 NULL。这样可以确保程序的没有那个地方会再使用无效指针。其实就是,访问一个已经被删除的对象地址,将引起程序异常。如下代码展示如何清除一个指针指向的对象:/ Create objectCVehicle* pVehicle = new CVehicle();delete pVehicle; / Free pointerpVehicle = NULL; / Set pointer with NULL在释放一个句柄之前,务必将这个句柄复制伪 NULL (0 或则其他默认值)。这样能够保证程序其他地方不会重复使用无效句柄。看看如下代码,如何

15、清除一个 Windows API 的文件句柄:HANDLE hFile = INVALID_HANDLE_VALUE; / Open filehFile = CreateFile(_T(example.dat), FILE_READ|FILE_WRITE, FILE_OPEN_EXISTING);if(hFile=INVALID_HANDLE_VALUE)return FALSE; / Error opening file/ Do something with file/ Finally, close the handleif(hFile!=INVALID_HANDLE_VALUE)Close

16、Handle(hFile); / Close handle to filehFile = INVALID_HANDLE_VALUE; / Clean up handle下面代码展示如何清除 File *句柄:/ First init file handle pointer with NULLFILE* f = NULL;/ Open handle to fileerrno_t err = _tfopen_s(_T(example.dat), _T(rb);if(err!=0 | f=NULL)return FALSE; / Error opening file/ Do something with

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号