Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

调试技术

From Wiki
Jump to: navigation, search
Article Metadata

文章
dougcn 在 22 Jun 2008 创建
最后由 hamishwillee 在 30 May 2013 编辑

调试技术

Contents

模拟器不显示Panic细节

若Panic发生了,除非在指定的位置有一个名叫“ErrRd”的文件,否则模拟器不会显示Panic的细节。这使得很难知道是什么引起Panic。

Panic.jpg

在SDK 3rd版以前,ErrRd文件必须手工创建,但从3rd版以后,这个文件可以默认在目录“C:\Symbian\9.2\S60_3rd_FP1\Epoc32\winscw\c\resource”下找到。有了ErrRd,Panic发生时的输出像这样:

Panic with ErrRd.jpg

提示: 如果即使使用3rd版的SDK,ErrRd文件也找不到,那就启动模拟器,选择 Tools > Preferences,然后勾上Extended panic code file。

使用断言检测Bug

使用断言检测所做的“代码是正确的”的假设,例如: 对象的状态,期望的函数参数和返回值等。Symbian OS中定义了两个断言宏: __ASSERT_ALWAYS 和__ASSERT_DEBUG。它们之间的区别是__ASSERT_DEBUG不会影响产品代码而__ASSERT_ALWAYS会。

这是一个如何使用__ASSERT_DEBUG宏的例子:

void TestValue(TInt aValue)
{
_LIT(KPanicCategory, "TestValue");
__ASSERT_DEBUG((aValue >= 0), User::Panic(KPanicCategory, 99));
// Do something with aValue
// ...
}

上例中,如果参数aValue小于0,抛出"Panic -99"。

注: 断言宏默认不抛Panic, 允许你来决定断言失败时调用什么过程。尽管如此,这种情况下你应该总是抛出Panic而不是返回错误或Leave。

因为上例使用__ASSERT_DEBUG宏,只在debug编译时才检测aValue。如果有必要在产品代码中也检测参数,就应当用__ASSERT_ALWAYS。

当你不希望外部调用者需要跟踪Panic时,使用__ASSERT_DEBUG的一个替代品: ASSERT宏。ASSERT完全象是断言宏,除了它不要要你提供panic类别或描述符。

这里是该宏的定义,来自e32def.h文件:

#define ASSERT(x) __ASSERT_DEBUG(x, User::Invariant())

这是一个如何使用ASSERT宏的例子:

void TestValue(TInt aValue)
{
ASSERT(aValue >= 0);
// Do something with aValue
// ...
}

使用__UHEAP_MARK和__UHEAP_MARKEND宏检测内存泄漏

检测你的代码正确地管理堆内存(换言之,不泄漏内存)的一个可能性是使用__UHEAP_MARK和__UHEAP_MARKEND宏。

GLDEF_C TInt E32Main()
{
// Start checking memory leaks
__UHEAP_MARK;
 
// Create a fixed-length, flat array, which contains 10 integers
CArrayFixFlat<TInt>* fixFlatArray;
fixFlatArray = new(ELeave) CArrayFixFlat<TInt>(10);
// Array is not deleted, so memory will leak
 
// Stop checking memory leaks and cause a panic if there is a leak
__UHEAP_MARKEND;
 
return KErrNone;
}

由于数据未被删除和内存泄漏检测宏,上例代码在应用程序关闭时将引起一个Panic,如下图所示:

Memory leak MACRO.jpg

值得一提的是堆检测宏只编译进debug版,因此可以安全地留在产品代码中而不会影响代码的大小或速度。

对象不变性宏

有两个宏允许你检查对象的状态: __DECLARE_TEST 和 __TEST_INVARIANT。在实践中,它们被用来使程序员先创建一个不变性测试函数,然后在需要检测对象状态的函数的开头和结尾调用之,这是典型的做法。

class CLivingPerson : public CBase
{
public:
enum TGender {EMale, EFemale};
public:
CLivingPerson(TGender aGender);
~CLivingPerson();
public:
void SetAge(const TInt aAge);
private:
TGender iGender;
TInt iAgeInYears;
__DECLARE_TEST; // Object invariance testing
};
 
CLivingPerson::CLivingPerson(TGender aGender) : iGender(aGender) {}
CLivingPerson::~CLivingPerson() {}
 
void CLivingPerson::SetAge(const TInt aAge)
{
// Set age and check object invariance
__TEST_INVARIANT;
iAgeInYears = aAge;
__TEST_INVARIANT;
}
 
void CLivingPerson::__DbgTestInvariant() const
{
#ifdef _DEBUG // Built into debug code only
// Person should be either male or female
ASSERT((iGender == EMale) || (iGender == EFemale));
 
// Person's age shouldn't be negative
ASSERT(iAgeInYears >= 0);
#endif
}

由于上例使用ASSERT宏,若对象状态不正确时就抛出"USER 0"Panic。

用期望的弹出项检测清除栈的不正确使用

清除栈中的对象在不再有机会被Leave成孤儿时应被弹出。因此,弹出通常恰好发生在对象被删除之前。一般使用PopAndDestroy函数代替Pop函数,因为它确保对象一弹出就被删除,避免了内存泄漏的可能性。CleanupStack::Pop 和 CleanupStack::PopAndDestroy都有一个重载版本,允许调用者声明“期望的弹出项”,指明该项应从栈中弹出。在期望的弹出项不匹配所弹出的项时,将抛出"E32USER-CBase 90" Painc。推荐使用这两个重载版本,因为它们帮助检测清除栈的不正确使用。

CClass* obj = new(ELeave) CClass;
CleanupStack::PushL(obj);
// ...
CleanupStack::PopAndDestroy(obj); // Panics if ‘obj’ not on top

注: 在发行版编译时,期望弹出项的检测将被禁用,因此使用它们在二进制大小和效率方面都不会影响发行版编译。

内部链接

This page was last modified on 30 May 2013, at 04:42.
110 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×