Symbian细节一

 

== 模拟器不显示Panic细节 ==

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

Symbian调试技术

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

Symbian调试技术

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

 

== 使用断言检测Bug ==

使用断言检测所做的“代码是正确的”的假设,例如: 对象的状态,期望的函数参数和返回值等。

Symbian OS中定义了两个断言宏: __ASSERT_ALWAYS 和__ASSERT_DEBUG。它们之间的区别是__ASSERT_DEBUG不会影响产品代码而__ASSERT_ALWAYS会。

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

view plaincopy to clipboardprint?

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文件:

view plaincopy to clipboardprint?

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

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

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

view plaincopy to clipboardprint?

void TestValue(TInt aValue)

{

ASSERT(aValue >= 0);

// Do something with aValue

// ...

}

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

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

view plaincopy to clipboardprint?

GLDEF_C TInt E32Main()

{

// Start checking memory leaks

__UHEAP_MARK;

// Create a fixed-length, flat array, which contains 10 integers

CArrayFixFlat * fixFlatArray;

fixFlatArray = new(ELeave) CArrayFixFlat (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,如下图所示:

Symbian调试技术

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

== 对象不变性宏 ==

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

view plaincopy to clipboardprint?

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。

posted @ 2010-04-09 13:44  秋天的风  阅读(189)  评论(0编辑  收藏  举报