分享
 
 
 

Assert使用-初级

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

T-提示 Z-总结 Lx-分类 CODE-代码

/////////////参考《Debugging Windows Programs》-DWP 《游戏编码精粹》

////////////

编译器-通过静态分析代码来查错.

断言-程序自己自动检测运行时刻错误.

提示

T-断言是能让错误在运行时刻暴露在程序员面前的布尔调试语句.

T-使用断言能使问题早日发现,尽量在促无发源地附近就能够检测道错误.

T-使用断言来验证你的程序是否有效,但是记住,有效和正确并不相等. //日期的有效和正确

T-断言不能代替细致的测试.

T-保持断言的简单性.好的覆盖比复杂的检测更重要.

类型

L1-ANSI C断言.

assert函数 需包含 <assert.h> 链接C运行时刻函数库 定义NDEBUG符号驱动

显示失效表达式 路径名长度有限

L2-C运行时刻函数库断言

需包含 <crtdbg.h> 链接C运行时刻函数库 是VC++中的特殊断言/不是VC++自带

_ASSERT 不显示失效表达式

_ASSERTE 显示失效表达式 不支持Unicode

CODE-////from crtdbg.h

#define _ASSERT(expr) do { if (!(expr) && (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, NULL))) _CrtDbgBreak(); } while (0)

#define _ASSERTE(expr) do { if (!(expr) && (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, #expr))) _CrtDbgBreak(); } while (0)

T-_ASSERTE宏显示了失效断言,更加方便,并能提供一种保护机制,使你不会意外调试了不被调试的问题.

Z-在C运行时刻函数库中的断言里,_ASSERTE宏是最好的选择.

L3-MFC库的断言

ASSERT 宏和 _ASSERT 宏显示的消息框相同. 即使出现了WM_QUIT消息也能显示断言失效消息框.

CODE-

////from Afx.h

#define ASSERT(f) do { if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) AfxDebugBreak(); } while (0) ////from Afxver.h

#define AfxDebugBreak() _CrtDbgBreak()

////from Afxassert.cpp

BOOL AFXAPI AfxAssertFailedLine(LPCSTR lpszFileName, int nLine);

mfc还提供了 ASSERT 宏的几个变种.

更多MFC断言宏

L31-VERIFY

使用之的唯一原因: 它的保留程序代码的能力.

妨碍防御性编程(defensive programming)

L32-ASSERT_VALID

决定一个指向 CObject 派生类的对象的指针是否有效.

通过调用重载的 AssertValid 函数来决定 CObject 派生类的对象是否有效.

还进行了其它几个检查,增强了健壮性.

CODE- from Afx.h ////DWP-P73

#define ASSERT_VALID(pOb) (::AfxAssertValidObject(pOb, THIS_FILE, __LINE__))

T-在使用 CObject 派生类的对象之前都要调用 ASSERT_VALID 宏

L33-ASSERT_KINDOF

验证指向 CObject 派生类的对象的指针是否从特殊类中派生来.

CODE-ASSERT_KINDOF/////

#define ASSERT_KINDOF(class_name, object) ASSERT((object)->IsKindOf(RUNTIME_CLASS(class_name)))

T-总是在调用 ASSERT_KINDOF 宏之前调用 ASSERT_VALID 宏

eg-

CMyDocument * CMyView::GetDocument(){

ASSERT_VALID(m_pDoc);

ASSERT_KINDOF(CMyDocument, m_pDoc); //ASSERT(m_pDoc->IsKindOf(RUNTIME_CLASS(CMyDocument)));

......}

T-使用 ASSERT_KINDOF 宏检测编译器可能错过的对象类型问题.

L34-ASSERT_POINTER ASSERT_NULL_OR_POINTER

当指针不能为空的时候使用 ASSERT_POINTER; 否则使用 ASSERT_NULL_OR_POINTER

CODE-////from Afx.h

#define ASSERT_POINTER(p, type) ASSERT(((p) != NULL) && AfxIsValidAddress((p), sizeof(type), FALSE))

#define ASSERT_NULL_OR_POINTER(p, type) ASSERT(((p) == NULL) || AfxIsValidAddress((p), sizeof(type), FALSE))

BOOL AFXAPI AfxIsValidAddress(const void* lp,

UINT nBytes, BOOL bReadWrite = TRUE);

BOOL AFXAPI AfxIsValidString(LPCWSTR lpsz, int nLength = -1);

BOOL AFXAPI AfxIsValidString(LPCSTR lpsz, int nLength = -1);

以上两个函数都是对 IsBadReadPtr、IsBadWritePtr和IsBadStringPtr API 的简单封装.

L4-ATL断言

<Atlbase.h> 包含 <crtdbg.h>

ATLASSERT 默认实现为 _ASSERTE 可方便地使用自定义的断言.

T-在ATL程序中使用ATLASSERT;用MFC时选择ASSERT宏.

CODE-断言的源代码

/////DWP-P69

T-移植代码的时候,也移植断言

策略

T-要想有效利用断言需要一定的策略,不要随意地把断言分布道你的代码里面,而是遵从某些已经建立起来的模式.

T-"对整个时间都下断言",也就是说,不要试图选择哪一个断言要发现错误,根据你的断言策略断言一切.

L1-什么需要断言

L2-什么不需要断言

不变关系

L1-类不变关系

T-设计程序的同时就设计不变关系.在写代码之前理解它们,并且为它们建立文档.

T-公有成员函数比私有和保护的成员函数需要更全面的断言.

在函数进/出口使用断言,也不能保证中间变的临时无效.

模式

T-使用最能匹配你的数据的断言.

L1-函数参数断言

检查函数参数的有效性,也可以对作为隐式参数的全局变量采用同样的检查.

eg-////DWP-P86

_ASSERTE(value <= maxValue); ...

L2-CObject函数断言

对公有函数 ASSERT_VALID(this);

对私有函数 对其使用到的成员变量 断言

对复杂的函数 在其开头,结尾都使用断言 ASSERT_VALID(this);

对操作符函数 确保不是对自己操作 _ASSERTE(pObject != this)

AssertValid() 1.baseclass::AssertValid(); 2.对自己的成员变量断言 3.类不变关系断言

L3-派生数据断言

eg-////DWP-P89

L4-逻辑断言

1.switch-case 2.while(someloop) 3.经过复杂运算后,断言运算结果.(用不同的算法)

4.内存断言 _ASSERTE(_CrtCheckMemory());

L5-Windows API断言

处理消息时,在消息出错时断言. 对从 wParam, lParam 派生的参数使用断言.

eg-

1._ASSERTE(IsWindow(hWnd));

2.HWND hChildwnd = (HWND)wParam; _ASSERTE(IsWindow(hChildwnd));

3.HDC hDC = (HDC)wParam; _ASSERTE(GetObjectType(hDC) == OBJ_DC);

4.BYTE *buffer = (BYTE *)lParam; ASSERT_POINTER(buffer, BYTE);

T-总要为那些不清洗的断言做出注释,给别人和自己一个目前情况的线索.

T-充分实现 AssertValid 函数, 不要使用默认实现.

T-通过 AssertValid 函数检查对象的类不变关系.对简单的数据成员使用功能强大的断言;而对集合数据成员采用浅层检查.(shallow check)

避免出现断言"瀑布" (cascade)

防御性编程 (Defensive Programming)

T-不正确地使用断言会导致错误.断言是用来接示错误的,而不示用来纠正运行时刻错误的.

T-垃圾输入不应该导致垃圾输出.

T-Debug 版本和 Release 版本应该一样.//只用断言,没防御性编程很可能会导致不一致.

T-如果你的程序是防御性的,别忘了使用断言;如果你使用了断言,也别忘了防御性编程.

eg- if (!complexExpression){ _ASSERTE(FALSE);...}

if (FALIED(someFunction()){ _ASSERTE(!"the problem is XXX");

T-不要把不相关的检查放在同一个断言语句中.

使用技巧

L1- assert(scr != 0 && "FunName: scr point is NULL.");

L2- assert(!"FunName: the reason."); // == assert(0);

L3- #define Assert(a, b) assert(a && b)

Assert(scr != 0, "FunName: scr point is NULL.");

L4-重定向输出

int previousReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);

ASSERT_VALID(pDoc);

//....

if (previousReportMode != -1) _CrtSetReportMode(_CRT_ASSERT, previousReportMode);

L5-使用 GetObjectType 函数

_ASSERTE(GetObjectType(hBrush) == OBJ_BRUSH); //

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有