首页 > 其他分享 >【C语言】assert.h——断言

【C语言】assert.h——断言

时间:2024-06-15 23:29:03浏览次数:21  
标签:__ 断言 NDEBUG C语言 assert expression 调试


文章目录


断言是一种用于在程序执行过程中进行调试的工具,能够帮助开发者验证程序的某些假设是否为真。如果断言失败,程序会终止,并输出一个错误消息,通常包含出错的文件名和行号。这对于调试和测试非常有帮助。

主要内容

assert是一个宏,并不是函数。assert 宏接受一个表达式作为参数,如果该表达式的值为假(0),它会:

  1. 打印一条错误信息,指出断言失败的表达式,以及出错的文件名和行号。
  2. 调用 abort 函数终止程序执行。

具体的实现可以简单概括如下:

#define assert(expression) ((expression) ? (void)0 : __assert_fail(#expression, __FILE__, __LINE__))

void __assert_fail(const char *expr, const char *file, int line) {
    fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\\n", expr, file, line);
    abort();
}
/*
    助于理解 assert 功能
*/

调试和发布模式

在调试模式下,断言可以帮助捕捉程序中的错误。而在发布模式下,通常会禁用断言,以提高程序性能。可以通过定义 NDEBUG 宏来禁用断言:

#define NDEBUG    // 使用时一定要在包含assert库函数前定义
#include <assert.h>

一旦定义了 NDEBUGassert 宏将被定义为空操作,不会进行任何检查或中断程序:

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

使用示例

#include <stdio.h>
#include <assert.h>

int main() {
    int x = 5;
    assert(x == 5);  // 断言成功,不会中断程序
    printf("x is 5\n");

    x = 3;
    assert(x == 5);  // 断言失败,程序终止
    printf("This line will not be executed.\n");

    return 0;
}

/*
    在这个示例中,第一次断言 x == 5 是成功的,程序继续执行并输出 "x is 5"。第二次断言 x == 5 失败,程序会终止并输出错误信息。
*/

用法总结与注意事项

  1. 每个assert只检验一个条件:同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败

  2. 有的地方,assert不能代替条件过滤

  3. 只用于调试:断言主要用于调试阶段,确保代码逻辑的正确性。在发布版本中,通常会禁用断言,因此不要依赖断言来处理运行时错误或进行关键性检查。

  4. 不要在断言中有副作用:断言表达式中不应包含会改变程序状态的操作。

    // 错误示例
    assert(free(ptr) == 0);  // 这样写会导致发布版本中 free 函数不执行
    
    /* 例如,不要在断言中进行函数调用或修改变量的操作,因为在发布版本中这些操作可能不会执行。 */
    
  5. 条件表达式要简单明确:断言的条件表达式应简单明了,确保容易理解和调试。复杂的表达式可能会导致调试困难。

  6. 不要在生产代码中依赖断言:断言不应替代常规的错误处理机制。对于需要在生产环境中处理的错误,应使用适当的错误处理代码(如 if 语句和错误码)。

  7. 正确使用 NDEBUG 宏:在发布版本中,通过定义 NDEBUG 宏来禁用断言。这可以在编译选项中定义,或在源代码中定义:

    #define NDEBUG
    #include <assert.h>
    
  8. 避免在性能关键的代码中使用断言:虽然断言在调试阶段很有帮助,但在性能关键的代码路径中使用断言可能会影响调试阶段的性能。可以在调试阶段临时移除或减少这些断言,以进行性能测试。

  9. 保证断言条件的重要性:断言条件应当是真正的重要检查,而不是无关紧要的小检查。这些条件应反映代码的关键假设或不变量。

  10. 文档化断言:在复杂或关键的代码中,记录断言的目的和含义,帮助其他开发者理解断言的意图和背景。

标签:__,断言,NDEBUG,C语言,assert,expression,调试
From: https://blog.csdn.net/hdz_wiz_csdn/article/details/139707358

相关文章

  • C语言数据结构实现-双向链表
    前面学习了如何创建一个双向链表,本节学习有关双向链表的一些基本操作,即如何在双向链表中添加、删除、查找或更改数据元素。本节知识基于已熟练掌握双向链表创建过程的基础上,我们继续上节所创建的双向链表来学习本节内容,创建好的双向链表如图1所示:双向链表添加节点根据数据添......
  • 学习C语言两个月后的收获(篇目二) #超详细的scanf() 讲解-->基本用法、scanf() 的返回值
    一.scanf1.基本用法:scanf()读取用户的键盘输入 ---->程序在运行到这个语句的时候,会停下来,等待用户从键盘输入。当用户输入数据之后按下回车,scanf()就会处理用户的输入,将其存入变量。 scanf()是库函数,其头文件是<stdio.h>    (注:标准输入一般是键盘;标准输出......
  • C语言面试题
    1.static的作用1.修饰全局变量:不可以被外部文件访问,只可以在本文件中使用,限定它的作用域2.修饰函数:不可以被外部文件访问,只可以在本文件中使用,限定函数的作用域如果想要其他文件可以引用本地的函数,则要在函数定义时使用关键字,extern,表示该函数是外部函数可以被其他文件调......
  • 自学c语言的第一天
    高考完,终于有时间去学自己喜欢的编程,就先从c语言开始学起。首先,先配置好操作环境,下载好工具,决定从MSVC2022开始启动创建项目写自己的第一个c语言代码(祖宗之法不可变,“halloworld”)试运行(一次成功!!)稍微汇总一下自己学到的知识点:1、main是主函数,相当于代码运行的大门,一......
  • C语言:头歌课程设计(未完结,慎入)
    第1关:【课程设计】Init任务描述你需要将一系列的学生期末考试信息进行存储(学生人数不会超过100)。每个学生的信息包括:姓名(由firstname和lastname两部分组成,例如JingyuLI,first_name="Jingyu"last_name="LI");学号(12位数字组成,开头4位为2022、2021、2020);C......
  • C语言简单学习(obsidian打开)
    ##变量与类型###整数C给我们提供了下列定义整数的类型:-`char`-`int`-`short`-`long`通常,你很可能会使用 `int` 保存整数。但是在某些情况下,你或许想在其它三个选项中选取合适的类型。`char` 类型通常被用来保存ASCII表中的字母,但是它也可以用来保存 `-128......
  • 初识C语言难点~~指针变量
    目录前言 一、什么是指针变量二、定义指针变量1、代码12、代码2(通过指针变量取得数据) 三、通过指针变量来交换主函数两个变量1、【正确示例】2、【错误示例】四、总结 前言大家好又见面了!!今天要说的是指针变量。 一、什么是指针变量指针变量是一种特殊的变......
  • 初识C语言~~查找票数最高候选人
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、题目描述二、解题思路三、编写代码总结前言提示:这里可以添加本文要记录的大概内容:大家好又见面喽!!今天是刷题,二话不说开干。提示:以下是本篇文章正文内容,下面案例可供参考一、题目......
  • C语言----C语言内存函数
    1.memcpy--内存拷贝--使用和模拟实现 //memcpy基本格式://目标空间地址原空间地址被拷贝的字节个数//void*memcpy(void*destination,constvoid*source,size_tnum);//因为内存拷贝拷贝的数据有:整型数据、结构体数据、结构体数据。......
  • C语言-位运算练习-4
    题目:编写程序,接受两个int类型的参数,一个是值,一个是位的位置,如果指定位的位置为1,该函数返回1,否则返回0源代码:#include<stdio.h>intbit_location(intint_bit,intint_loca);intmain(){intint_bit,int_loca;printf("请输入你要查询的数字和对应位置是否为1......