简述断言(assert)的优缺点_python assert函数用法[通俗易懂]

简述断言(assert)的优缺点_python assert函数用法[通俗易懂]目录🎍1.整体介绍🎍2.assert()的用法和机制🎍3.关于NDEBUG宏🎍4.使用assert()注意事项🎍4.1使用assert()时,被检测的表达式最好不要太复杂🎍4.2不

目录

🎍1.整体介绍

🎍2.assert() 的用法和机制

🎍3.关于NDEBUG 宏

🎍4.使用assert()注意事项

🎍4.1使用 assert() 时,被检测的表达式最好不要太复杂

🎍4.2不要用会改变环境的语句作为断言的表达式

感谢观看,敬请期待更好的作品吧。🎍


🎍1.整体介绍

assert()断言函数,用于在调试过程中捕捉程序错误

所在头文件:<assert.h>

函数原型:void assert (int expression);

参数:expression即要检测的表达式

返回值:无返回值

        “断言”在语文中的意思是“断定”、“十分肯定地说”,在编程中是指对某种假设条件进行检测,如果条件成立就不进行任何操作,如果条件不成立就捕捉到这种错误,并打印出错误信息,终止程序执行。

assert() 会对表达式expression进行检测:

        如果expression的结果为 0(条件不成立),那么断言失败,表明程序出错,assert() 会向标准输出设备(一般是显示器)打印一条错误信息,并调用 abort() 函数终止程序的执行。

        如果expression的结果为非 0(条件成立),那么断言成功,表明程序正确,assert() 不进行任何操作。

大部分编译器的格式如下所示:

Assertion failed: expression, file filename, line number

简述断言(assert)的优缺点_python assert函数用法[通俗易懂]

        要打印的错误信息的格式和内容没有统一的规定,这和标准库的具体实现有关(也可以说和编译器有关),但是错误信息至少应该包含以下几个方面的信息:

1.断言失败的表达式,也即expression;

2.源文件名称;

3.断言失败的代码的行号。

 

🎍2.assert() 的用法和机制

        在大部分编译器下,assert() 是一个宏;在少数的编译器下,assert() 就是一个函数。我们无需关心这些差异,只管把 assert() 当做函数使用即可。

        assert() 的用法很简单,我们只要传入一个表达式,它会计算这个表达式的结果:如果表达式的结果为“假”,assert() 会打印出断言失败的信息,并调用 abort() 函数终止程序的执行;如果表达式的结果为“真”,assert() 就什么也不做,程序继续往后执行。

下面是一个具体的例子:

#include <stdio.h>
#include <assert.h>
int main()
{
    int m, n, result;
    scanf("%d %d", &m, &n);
    assert(n != 0);  //写作 assert(n) 更加简洁
    result = m / n;
    printf("result = %d\n", result);
    return 0;
}

        本例用来计算两个数相除的结果,由于被除数不能为 0,所以我们加入了 assert() 来检测错误。

        如果输入100 20,那么 n 的值为 20,n != 0这个条件成立,assert() 不进行任何操作,最终的输出结果为:

简述断言(assert)的优缺点_python assert函数用法[通俗易懂]

 

        如果输入100 0,那么 n 的值为 0,n != 0这个条件不成立,assert() 就会报告错误,并终止程序执行,最终的结果如下所示:

简述断言(assert)的优缺点_python assert函数用法[通俗易懂]

🎍3.关于NDEBUG 宏

如果查看 <assert.h> 头文件的源码,会发现 assert() 被定义为下面的样子:

#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#define assert(e)  
    ((void) ((e) ? ((void)0) : __assert (#e, __FILE__, __LINE__)))
#endif

        这意味着,一旦定义了NDEBUG宏,assert() 就无效了。

        NDEBUG 是”No Debug“的意思,也即“非调试”。有的编译器(例如 Visual Studio)在发布(Release)模式下会定义 NDEBUG 宏,在调试(Debug)模式下不会定义定义这个宏;有的编译器(例如 Xcode)在发布模式和调试模式下都不会定义 NDEBUG 宏,这样当我们以发布模式编译程序时,就必须自己在编译参数中增加 NDEBUG 宏,或者在包含 <assert.h> 头文件之前定义 NDEBUG 宏。

        调试模式是程序员在测试代码期间使用的编译模式,发布模式是将程序提供给用户时使用的编译模式。在发布模式下,我们不应该再依赖 assert() 宏,因为程序一旦出错,assert() 会抛出一段用户看不懂的提示信息,并毫无预警地终止程序执行,这样会严重影响软件的用户体验,所以在发布模式下应该让 assert() 失效。

修改先前的代码,在包含 <assert.h> 之前定义 NDEBUG 宏:

#define NDEBUG
#include <stdio.h>
#include <assert.h>
int main()
{
    int m, n, result;
    scanf("%d %d", &m, &n);
    assert(n);
    result = m / n;
    printf("result = %d\n", result);
    return 0;
}

        当以发布模式编译这段代码时,assert() 就会失效。如果希望继续以调试模式编译这段代码,去掉 NDEBUG 宏即可。

🎍4.使用assert()注意事项

 

🎍4.1使用 assert() 时,被检测的表达式最好不要太复杂

以下面的代码为例:

assert( expression1 && expression2 && expression3);

        当发生错误时,assert() 只会告诉我们expression1 && expression2 && expression3整个表达式为不成立,但是这个大的表达式还包含了三个小的表达式,并且它们之间是&&运算,任何一个小表达式为不成立都会导致整个表达式为不成立,这样我们就无法推断到底是expression1有问题,还是expression2或者expression3有问题,从而给排错带来麻烦。

        这里我们应该遵循使用 assert() 的一个原则:每次断言只能检验一个表达式。

        根据这个原则,上面的代码应改为:

assert(expression1);
assert(expression2);
assert(expression3);

        如此,一旦程序出错,我们就知道是哪个小的表达式断言失败了,从而快速定位到有问题的代码。

🎍4.2不要用会改变环境的语句作为断言的表达式

请看下面的代码:

#include <stdio.h>
#include <assert.h>
int main()
{
    int i = 0;
    while(i <= 110)
    {
        assert(++i <= 100);
        printf("我是第%d行\n",i);
    }
    return 0;
}

        在 Debug 模式下运行,程序循环到第 101 次时,i 的值为 100,++i <= 100不再成立,断言失败,程序终止运行。

        而在 Release 模式下运行,编译参数中设置了 NDEBUG 宏(如果编译器没有默认设置,那么需要你自己来设置),assert() 会失效,++i <= 100这个表达式也不起作用了,while() 无法终止,成为一个死循环。

        定义了 NDEBUG 宏后,assert(++i <= 100)会被替换为((void)0)。

        导致程序在 Debug 模式和 Release 模式下的运行结果大相径庭的罪魁祸首就是++运算,我们本来希望它改变 i 的值,逐渐达到 while 的终止条件,但是在 Release 模式下它失效了。

修改这段不规范的代码也很容易,将++i移出 assert() 即可:

#include <stdio.h>
#include <assert.h>
int main()
{
    int i = 0;
    while(i <= 110)
    {
        ++i;
        assert(i <= 100);
        printf("我是第%d行\n",i);
    }
    return 0;
}

        如此,不管是 Debug 模式还是 Release 模式,每次循环 i 的值都会增加,逐渐达到 while 的终止条件时,结束循环。


感谢观看,敬请期待更好的作品吧。🎍

今天的文章简述断言(assert)的优缺点_python assert函数用法[通俗易懂]分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/77649.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注