而这正是契约设计(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 库的宏Listing 1. Embedded systems-friendly assertionsassert()
很少适用于嵌入式系统,因为它的默认行为(当传递给宏的整数表达式求值为 0 时)是打印一个错误信息并退出 。这两种行为对大多数嵌入式系统来说都没有什么意义 , 它们很少有屏幕可以打?。膊荒苷嬲顺觯ㄖ辽俨荒芟褡烂娉绦蚰茄顺觯?。因此,在嵌入式环境中,你通常必须定义你自己的断言,以适应你的工具并允许你自定义错误响应 。然而 , 我建议你在 "加强 "断言之前三思而后行,因为断言的很大一部分力量来自于其相对的简单性 。
#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 */
Listing 1 shows the simple embedded systems-friendly assertions that I’ve found adequate for a wide range of embedded projects. Listing 1 is similar to the standard <assert.h>
(<cassert>
in C++), except that the solution shown in Listing 1:- allows customizing the error response;
- conserves memory by avoiding proliferation of multiple copies of the filename string;
- provides additional macros for testing and documenting preconditions (
REQUIRE
), postconditions (ENSURE
), and invariants (INVARIANT
). (The names of the three last macros are a direct loan from Eiffel, the programming language that natively supports DbC.)
ASSERT()
macro (lines 28-29 of Listing 1) is very similar to the standard assert()
. If the argument passed to this macro evaluates to 0 (false), and if additionally the macro NASSERT
is not defined, then ASSERT()
will invoke a global callback onAssert__()
. The function onAssert__()
gives the clients the opportunity to customize the error response when the assertion fails. In embedded systems, onAssert__()
typically first monopolizes the CPU (by disabling interrupts), then possibly attempts to put the system in a fail-safe mode, and eventually triggers a system reset. (Many embedded systems come out of reset in a fail-safe mode, so putting them in this mode before reset is often unnecessary.) If possible, the function should also leave a trail of bread crumbs from the cause, perhaps by storing the filename and line number in a nonvolatile memory. (The entry to onAssert__()
is also an ideal place to set a breakpoint if you work with a debugger. TIP: Consult your debugger manual on how you can hard-code a permanent breakpoint in onAssert__()
.)Compared to the standard assert(), the macro ASSERT() conserves memory (typically ROM) by passing
THIS_FILE__
(Listing 1, line 26) as the first argument to
推荐阅读
- 《英雄联盟》英雄亚索怎么玩(各个英雄如何评价亚索)
- MySQL数据库的性能分析 ---图书《软件性能测试分析与调优实践之路》-手稿节选
- 《新录用公务员任职定级规定》咨询 新录用公务员任职定级规定2019
- 《正义联盟》中超人是怎么死的
- 《正义联盟》超人那么厉害,是怎么死的(正义联盟超人实力怎样)
- 《三国演义》中曹操的大将许褚是怎么死的(三国许褚做了哪些大事)
- 33 《吐血整理》高级系列教程-吃透Fiddler抓包教程-Fiddler如何抓取WebSocket数据包
- 《火影忍者》:二代火影真正的死因是什么为什么说是不会解开的迷题
- JVM运行时数据区域详解
- 《火影忍者》里,二代火影是怎么死的(二代火影为什么打不过金银角)