PSP 开发/基本错误处理
随着程序复杂度的增加,PSP 上潜在的错误数量呈指数级增长。C 语言能够在性能受限的系统上开发功能性程序。PSP 是一款功能强大的设备,与 PS2 的性能相当,而 PS Vita 的性能则超过 PS2。作为一款游戏机,它对未定义行为、错误分配的数据、不正确的指针运算以及空指针非常敏感,这比电脑更严重。问题源于游戏机是嵌入式的,以特定的方式运行,没有用户自制软件开发的能力。有一个专有的系统专为生产力和调试环境而设计。
注意 所有未来的文章都将使用以下函数。
运行时错误是最容易处理的。运行时错误发生在系统对数据进行操作时,其结果返回不正确或对无效数据(页面/段错误)进行操作。程序员有责任正确编写程序,以便运行时错误不存在或在系统无法继续运行的情况下进行处理。如果能够有幸编写物理 UMD 光盘,那么程序员在处理诸如读取时玩家取出光盘、无法读取、掉落 PSP 等等情况时,就会显得无能为力。在使用 UMD 的应用程序中,一个示例错误可能是用户在读取 UMD 时将其取出。程序需要提醒用户操作已取消并返回到正常状态。
在 Python 和 Java 中,程序员会熟悉 try catch 语句。但是,C 语言有自己的处理方式。 C 语言中的错误处理 文档记录了一些错误检查策略。重要的是要理解文章中给出的建议之外的内容。在 #PSPDEV 错误 中,未定义几乎可以直接作为 C 错误的同义词。C 错误往往会在运行时完全崩溃。应该使用一种方法来确定问题所在。C 错误和 PSPDEV 错误之间的区别在于,使用库的正确性与语法或内存相关问题之间的区别。添加到其他语言中的 try-catch 系统是错误的普遍性和运行时错误处理策略的产物,它将中断的生产力转变为生产力。
运行时错误有三种不同的模式:预期、意外和未定义。预期错误可能发生在系统检查文件是否存在以加载到系统中时。系统将返回一个状态。意外错误可能发生在文件中的数据损坏时 - 程序无法使用此文件。系统无法立即检测到这一点,否则可能会崩溃。这两个错误都意味着程序无法继续执行请求的操作。与继续使用不正确的数据(可能会导致空指针和数据对齐错误)相比,一种解决方案是停止操作并提醒用户。未定义错误是指编写了语法上正确且理论上正确的代码,但会导致崩溃。例如,释放分配的内存并将指针设置为 0,然后尝试使用该变量指针可能会导致程序崩溃。意外错误和未定义错误之间的区别在于,未定义错误不会进入可以发生意外错误的阶段。
在 PSPDEV 中,许多函数返回一个 int,它表示特定值的错误。有些程序通过图形库将错误显示给用户。在 main.c 中,有一个功能位置可以放置单个帮助程序函数,这些函数接受常用参数,并将它们显示给用户。本文介绍了一种在发生崩溃的情况下,以一种干净的方式处理错误的方法。这样做的原因可以追溯到,无法制作一个“一劳永逸”的错误检查函数,同时还要能够绕过它们,以便程序仍然能够正常工作。try-catch 语句的诞生正是由于这个问题,它能够检查和监听预期或意外错误,并且程序有关于如何绕过它们的指令。C 语言没有 try-catch 语句,因此本文旨在介绍一种更具创意的方式来处理错误。
以下函数的工作原理是,它围绕着 main() 函数中的任何位置的主线程。由于调试模式通常在主线程上运行,该线程使程序保持活动和更新,因此直接在每个打印的新行末尾写入错误消息,并无限期地挂起主线程以使其崩溃是有意义的。这使得能够读取错误消息。可以通过提供一个具有相关通用错误处理参数的方法来实现回调系统(而不是挂起线程以处理类似于 try-catch 的错误)。最好确保 vblank 以便能够在任何地方调用此函数。以下函数最适合预期和意外错误。
main.c
void crash(int error, const char* crasher, const char* message) {
sceDisplayWaitVblankStart();
printf("Error (%d) : %s\n", error, crasher);
printf("%s\n", message);
sceKernelSleepThread();
}
PSP 最大的缺陷是崩溃时没有输出。需要实现一个工具来帮助找出潜在的未定义错误。除此之外,还需要模拟强制崩溃。因为一行代码可能会崩溃,在它之前输出文本并挂起线程会导致没有崩溃和文本显示。但是,如果尝试在崩溃代码行之后打印,线程将不会挂起,也不会显示任何文本。利用这种逻辑,可以将打印-挂起函数移到可疑代码行周围,以了解哪一行代码导致崩溃。但是,修复并不简单,因为之前的行可能会造成崩溃代码行崩溃的原因。
以下代码是预期和意外错误函数代码的衍生,但内容更少。几乎没有有用的逻辑输出可以输出。但是,如果有必要,可以添加参数,但这会增加填写参数的复杂性。相反,当找到崩溃的行时,打印相关的变量可能会节省时间和精力。这样做也有助于进一步识别问题。对于未找到的错误进行 printf 操作,需要检查与崩溃无关的变量的值。
main.c
void test_crash() {
sceDisplayWaitVblankStart();
printf("No crash occured.");
sceKernelSleepThread();
}
使用 pspDebug,可以安装一个充当错误处理程序的函数。有了错误处理程序,就会有 PSP 的输出。这有助于调试发生了什么。未来的文章可能会在某些情况下使用它,例如有问题的示例。这就像带 stderr 的 try catch 语句 - 当发生错误时,会收集数据并说明问题。
- 预期/意外
- main.c : http://pastebin.com/Lw3n2WnE
- 未定义
- main.c 测试用例 1 : http://pastebin.com/eWvZR5Pd
- main.c 测试用例 2 : http://pastebin.com/DzUH4X3j