how to use assert() efficiently

Context: I write server software for a living, the kind that stays up for weeks before the next version is loaded. So my answers may be biaised toward highly defensive code.

The principle.

Before we delve into the specifics of where to use assert, it's important to understand the principle behind it.

assert is an essential tool in Defensive Programming. It helps validating assumptions (assert them actually) and thus catch programming errors (to be distinguished from user errors). The goal of assert is to detect erroneous situations, from which recovery is generally not immediately possible.

Example:

char const* strstr(char const* haystack, char const* needle) {
  assert(haystack); assert(needle);

  // ...
}

Alternatives.

In C ? There is little alternative. Unless your function has been designed to be able to pass an error code or return a sentinel value, and this is duly documented.

In C++, exceptions are a perfectly acceptable alternative. However, an assert can help produce a memory dump so that you can see exactly what state the program is in at the moment the erroneous situation is detected (which helps debugging), while an exception will unwind the stack and thus lose the context (oups...).

Also, an exception might (unfortunately) get caught by a high level handler (or an unsavory catch from a fellow developer (you would not do that, of course)), in which case you could miss completely the error until it's too late.

Where NOT to use it.

First, it should be understood that assert is only ever useful in Debug code. In Release, NDEBUG is defined and no code is generated. As a corollary, in Release assert has the same worth as a comment.

  • Never use it for checks that are necessary to the good behavior of the software. Error conditions should be checked and dealt with. Always.

Second, it should be understood that malformed input is part of your life. Would you want your compiler display an assert message each time you make an error ? Hum! Therefore:

  • Never use it for input data validation. Input data should be validated and errors appropriately reported to the user. Always.

Third, it should be understood that crashes are not appreciated. It is expected of your program that it will run smoothly. Therefore, one should not get tempted to leave asserts on in Release mode: Release code ends up in the end user hands and should never crash, ever. At worst, it should shutdown while displaying an error message. It is expected that no user data is lost during this process, and even better if upon restarting the user is taken back to where she was: that is what modern browsers do, for example.

  • Never leave asserts on in Release.

Note: for server code, upon "hitting" an assertion, we manage to get back in position for treating the next query in most cases.

Where to use it.

assert is on in Debug mode, and so should be used for Debugging. Whenever you test new code, whenever your test suite run, whenever software is in your (or your teammates) hands, whenever software is in you QA department hands. Asserts let you spot errors and gives you the full context of the error so that you can repair.

  • Use it during the development and testing cycles.

Even better. Since you know code will not be executed in Release you can afford to performexpensive checks.

Note: you should also test the Release binary, if only to check the performance.

And in Release ?

Well, in the codebase I work on, we replace the inexpensive asserts (the others are ignored) by specific exceptions that are only caught by a high level handler that will log the issue (with backtrace), return a pre-encoded error response and resume the service. The development team is notified automatically.

In software that is deployed, the best practices I have seen imply to create a memory dump and stream it back to the developers for analysis while attempting not to lose any user data and behave as courteously as possible toward the unfortunate user. I feel really blessed to be working server-side when I contemplate the difficulty of this task ;)

"undefined reference to `assert'" 这种报错通常出现在C/C++程序链接阶段,当你试图链接包含assert宏定义的源文件时,但链接器找不到相应的assert函数的定义。这可能有以下原因: 1. **assert未包含**: 确保你在需要用到assert的地方包含了头文件`<assert.h>`。例如,在C标准库中,`#include <assert.h>`通常会在项目开始处就加入。 ```c #include <assert.h> ``` 2. **构建配置问题**: 如果你是用IDE或者预处理器管理宏,确认构建配置正确地将assert设为了可用。有些工具默认可能会禁用assert,以便于生产环境优化。 3. **静态链接还是动态链接**: 如果你的应用使用了静态链接(比如 `-static` 或 `-Wl,-Bstatic`),并且`libassert.a`之类的库没有添加到链接中,assert就无法找到。在这种情况下,你应该链接动态库(如 `-lassert` 或 `-Wl,-Bdynamic`)。 4. **交叉编译**: 对于特定平台的交叉编译,你可能需要查找对应的系统库或编译选项来支持assert。 5. **代码位置**: 如果你在库函数中使用了assert,而在主程序或应用程序入口点处没有链接到该库,也会出现这个错误。确保在编译主程序时正确传递了依赖的所有库。 解决这类问题的一般步骤是检查编译选项、链接命令和包括路径,确保所有的引用都能正确找到。如果你正在使用像Makefile或CMake这样的构建系统,可能还需要检查相关的构建规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值