关于c++中断言assert的说明 『转』

本文详细解析了C++中assert断言的使用方法与注意事项,包括其基本用法、常见技巧、与ASSERT/ASSERTE头文件的区别、与错误校验的关系,以及如何正确应用于代码中以提高程序的健壮性和可维护性。

关于c++中断言assert的说明 『转』

assert(条件) ;
如果条件不满足则会弹出对话框 

技巧1 
assert(条件&&"说明信息"
由于对话框中会显示条件,因此可以利用这个特点显示说明信息,帮助定位错误 

技巧2 
assert(!"说明信息"
因为assert(0)肯定会显示对话框,可以帮助提示程序运行到哪里了,常用在switch case中 对于不可能达到的default的说明和提示:

default: assert(!"should never get here!");

     return -1;

技巧3 
#define Assert(a,b) assert(a&&b) 
定义一个Assert宏,可以更好的使用技巧1 

技巧4 
#define Assert(条件,"说明信息") 
   if(条件){_asm{int 3}}    //满足条件中断

 

关于ASSERT 和 _ASSERTE头文件: 

 用法   :

   _ASSERT( booleanExpression );             

  _ASSERTE( booleanExpression );  

解释   : 这两个宏具有更加丰富的调试功能。

 

你真的会使用assert吗?

写这篇博客源于在阅读lighttpd源代码是遇到的一个关于assert应用的疑问。

在阅读lighttpd源代码时,发现比比皆是的对malloc的调用结果进行assert检查,比如:Buffer.c:

复制代码
buffer* buffer_init(void) {
    buffer *b;

    b = malloc(sizeof(*b));
    assert(b);

    b->ptr = NULL;
    b->size = 0;
    b->used = 0;

    return b;
}
复制代码

这里的assert(b)似乎有问题,实际release版本在运行中难道不会发生malloc返回NULL的情况吗?之后在阅读《Writing Solid Code 》一书时找到了答案。

对assert的基本用法就不再累述了,下面总结一下assert的实际应用的Recommended practice吧:

1、要使用断言对函数参数进行确认 

主要有以下情况:

  • 指针不是NULL的断言;
  • index值或size值不是负值或小于已知限值的断言;这一条也可以这么描述:要从程序中删去无定义的特性或者在程序中使用断言来检查出无定义特性的非法使用

 

2、每个断言必须在头文件中的函数功能描述的断言部分进行说明(不要浪费别人的时间 ─── 详细说明不清楚的断言 ),例如:

*  Asserts:
 *      'size' is no greater then LIMIT.
 *      'format' is not NULL.
 *      The function result is no greater than LIMIT.
 */

如果没有断言, 写 “Nothing”:

 *  Asserts:
 *      Nothing
 */
(以上的格式也许严格了一些,不过如果真的这么做,对代码的可阅读性会很有帮助)

3、断言和错误校验的区别

正确使用断言,必须要清楚程序错误(program errors)和运行时错误(run- time errors)之间的区别; 

  1. 一个程序错误是一个bug,永远不应该发生。
  2. 一个运行时错误是在程序运行的任何时候都可能会发生.

断言并不是一种处理运行时错误的机制。例如在需要输入正数的时候,用户输入了一个负数,如果用断言来检测这种情况就不是好的设计。对于这种情况需要用合适的错误检查和恢复处理的代码来进行处理。

再回到lighttpd中对malloc函数的返回值进行assert断言,我觉得也属于这个问题,这应该是一个运行时错误,而不是程序错误;所以,我觉得《C和指针》一书中对malloc返回NULL处理是通过一个错误检查分配器来处理的

4、断言和bug

断言大致分为前置条件(Preconditions)、后置条件(Postconditions)、不变性条件(Invariants)

如果前置条件不成立,发生Assertion violations,则调用该函数的代码存在bug,需要尽快找到并解决;

如果后置条件不成立,发生Assertion violations,则(函数的)实现代码存在bug,需要尽快找到并解决;

例如:

复制代码
void doBlah(int x)

{

    assert(x!=0);

    ....

} 
复制代码

这段代码说明这个函数的调用不可能传入参数0,如果发生这种情况,说明调用这个函数的代码存在bug

以上是自己的一点理解,欢迎高手指正!!!



### C++assert关键字的用法和功能 #### 1. 基本概念 `assert` 是 C++ 中用于调试程序的一种工具,主要用于在运行时验证某些条件是否成立。如果条件不成立,程序会中断执行并输出错误信息。这种机制可以帮助开发者快速发现并修复问题[^3]。 #### 2. 使用方法 `assert` 的基本语法如下: ```cpp #include <cassert> // 引入头文件 assert(condition); ``` - `condition` 是一个布尔表达式,表示需要验证的条件。 - 如果 `condition` 为 `false`,程序会终止并输出错误信息。 例如,在 C++ 中使用 `assert`: ```cpp #include <iostream> #include <cassert> int main() { int x = 7; x = 9; // 假设 x 被意外修改为 9 assert(x == 7); // 验证 x 是否仍为 7 std::cout << "断通过" << std::endl; return 0; } ``` 在这个例子中,当 `x` 不等于 7 时,程序会终止并显示错误信息[^3]。 #### 3. 关于禁用 `assert` 可以通过定义宏 `NDEBUG` 来关闭 `assert`,从而避免在生产环境中使用它。需要注意的是,定义 `NDEBUG` 必须在包含 `<cassert>` 头文件之前完成。 示例代码如下: ```cpp #define NDEBUG #include <iostream> #include <cassert> int main() { int x = 9; assert(x == 7); // 此断在定义了 NDEBUG 后将被忽略 std::cout << "断被忽略" << std::endl; return 0; } ``` #### 4. 运行时与编译时的区别 与 `static_assert` 不同,`assert` 是在运行时进行验证的,而 `static_assert` 则是在编译期间验证条件是否成立。这意味着 `assert` 只能在程序运行时捕获错误,而 `static_assert` 可以更早地发现问题[^2]。 #### 5. 功能和作用 `assert` 的主要功能是帮助开发者在开发阶段捕获逻辑错误或异常情况。它通常用于以下场景: - 验证函数的输入参数是否符合预期。 - 检查程序内部状态是否正确。 - 在单元测试中验证代码行为是否符合预期。 然而,`assert` 不应被用于处理用户输入或预期的异常情况。这些场景更适合使用异常处理机制(如 `try-catch`)[^3]。 #### 示例代码 以下是一个完整的 C++ 示例,展示如何使用 `assert` 验证函数输入: ```cpp #include <iostream> #include <cassert> double calculate_square_root(double x) { assert(x >= 0 && "输入值必须是非负数"); // 验证输入是否合法 return std::sqrt(x); } int main() { double result = calculate_square_root(16); // 正常调用 std::cout << "平方根: " << result << std::endl; // double error_result = calculate_square_root(-1); // 触发断错误 return 0; } ``` ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值