《Design by Contract for Embedded Software》 翻译( 三 )


The distinction between errors and exceptional conditions in any type of software (not just firmware) is important, because errors require the exact opposite programming strategy than exceptional conditions. The first priority in dealing with errors is to detect them as early as possible. Any attempt to handle a bug (as you would an exceptional condition) results in unnecessary complications of the code and either camouflages the bug or delays its manifestation. (In the worst case, it also introduces new bugs.) Either way, finding and fixing the bug will be harder.

在任何类型的软件(不仅仅是固件)中,区分错误和异常是很重要的,因为错误需要与异常完全相反的编程策略 。处理错误的首要任务是尽可能早地发现它们 。任何试图处理错误的行为(就像处理特殊情况一样)都会导致代码不必要的复杂化,要么掩盖错误,要么延迟其表现 。(在最坏的情况下,它还会引入新的错误 。) 无论怎样,发现和修复错误都会更难 。
Design by Contract (DbC)契约设计(DbC)
And here is where the Design by Contract (DbC) philosophy comes in. DbC, pioneered by Bertrand Meyer, views a software system as a set of components whose collaboration is based on precisely defined specifications of mutual obligations—the contracts.1 The central idea of this method is to inherently embed the contracts in the code and validate them automatically at run time. Doing so consistently has two major benefits: 1) It automatically helps detect bugs (as opposed to “handling” them), and 2) It is one of the best ways to document code.
而这正是契约设计(DbC)理念的体现 。DbC 是由 Bertrand Meyer 开创的,他将软件系统视为一组组件,这些组件的协作是基于精确定义的相互义务的规范--合同 1 。这样做有两个主要好处 。1)它自动帮助检测错误(而不是 "处理 "它们),2)它是记录代码的最佳方式之一 。
You can implement the most important aspects of DbC (the contracts) in C or C++ with assertions. The Standard C Library macro assert() is rarely applicable to embedded systems, however, because its default behavior (when the integer expression passed to the macro evaluates to 0) is to print an error message and exit. Neither of these actions makes much sense for most embedded systems, which rarely have a screen to print to and cannot really exit either (at least not in the same sense that a desktop application can). Therefore, in an embedded environment, you usually have to define your own assertions that suit your tools and allow you to customize the error response. I’d suggest, however, that you think twice before you go about “enhancing” assertions, because a large part of their power derives from their relative simplicity.
你可以用断言在 C 或 C++中实现 DbC 的最重要的方面(契约/合同) 。然而,标准 C 库的宏 assert() 很少适用于嵌入式系统,因为它的默认行为(当传递给宏的整数表达式求值为 0 时)是打印一个错误信息并退出 。这两种行为对大多数嵌入式系统来说都没有什么意义,它们很少有屏幕可以打印,也不能真正退出(至少不能像桌面程序那样退出) 。因此,在嵌入式环境中,你通常必须定义你自己的断言,以适应你的工具并允许你自定义错误响应 。然而,我建议你在 "加强 "断言之前三思而后行,因为断言的很大一部分力量来自于其相对的简单性 。
Listing 1. Embedded systems-friendly assertions
#ifndef qassert_h#define qassert_h/** NASSERT macro disables all contract validations * (assertions, preconditions, postconditions, and invariants). */#ifdef NASSERT /* NASSERT defined--DbC disabled */#define DEFINE_THIS_FILE#define ASSERT(ignore_)((void)0)#define ALLEGE(test_)((void)(test_))#else /* NASSERT not defined--DbC enabled */#ifdef __cplusplusextern "C"{#endif/* callback invoked in case of assertion failure */void onAssert__(char const *file, unsigned line);#ifdef __cplusplus}#endif#define DEFINE_THIS_FILE \static char const THIS_FILE__[] = __FILE__#define ASSERT(test_) \((test_) ? (void)0 : onAssert__(THIS_FILE__, __LINE__))#define ALLEGE(test_)ASSERT(test_)#endif /* NASSERT */#define REQUIRE(test_)ASSERT(test_)#define ENSURE(test_)ASSERT(test_)#define INVARIANT(test_) ASSERT(test_)#endif /* qassert_h */

经验总结扩展阅读