第十二章 C语言调试_assert断言函数

article/2025/10/3 14:39:58

在我们的实际开发过程之中,常常会出现一些隐藏得很深的BUG,或者是一些概率性发生的BUG,通常这些BUG在我们调试的过程中不会出现很明显的问题,但是如果我们将其发布,在用户的各种运行环境下,这些程序可能就会露出马脚了。那么,如何让我们的程序更明显的暴露出问题呢?这种情况下,我们一般都会使用 assert 断言函数,这是C语言标准库提供的一个函数,也就是说,它的使用与操作系统平台,调试器种类无关。我们只要学会了它的使用,便可一次使用,处处开花。

接下来我们来了解一下 assert 函数的用法,这个函数在 assert.h 头文件中被定义,在微软的 cl 编译器中它的原型是这样的:

#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) ) 

我们看到 assert 在 cl 编译器中被包装成了一个宏,实际调用的函数是 _wassert ,不过在一些编译器中,assert 就是一个函数。为了避免这些编译器差异带来的麻烦,我们就统一将 assert 当成一个函数使用。

我们来了解一下 assert 函数的用法和运行机制,assert 函数的用法很简单,我们只要传入一个表达式即可,它会计算我们传入的表达式的结果,如果为真,则不会有任何操作,但是如果我们传入的表达式的计算结果为假,它就会像  stderr (标准错误输出)打印一条错误信息,然后调用 abort 函数直接终止程序的运行。

现在我们在 Visual Studio 中创建一个工程,输入下面这段非常简单的代码:

 我们按 F5 启动调试:


我们看到,我们的输出窗口打印出了断言失败的信息,并且 Visual Studio 弹出了一个对话框询问我们是否继续执行。但是如果我们不绑定调试器,构建发布版程序,按 Ctrl + F5 直接运行呢?是的,这个 assert 语句就无效了,原因其实很简单,我们看看 assert.h 头文件中的这部分代码:

我们看到,只要我们定义了 NDEBUG 宏,assert 就会失效,而 Visual Studio 的默认的发布版程序编译参数中定义了 NDEBUG 宏,所以我们不用额外定义,但是在其他编译器中,我们在发布程序的时候就必须在包含 assert.h 头文件前定义 NDEBUG 宏,避免 assert 生效,否则总是让用户看到“程序已经停止运行,正在寻找解决方案 . . .”的 Windows 系统对话框可就不妙了。
下面我们来了解一下 assert 的常用情境以及一些注意事项。举个C语言文件操作的例子: 

 阅读代码,我们可以知道,如果我们错误的设置了读写权限,或者没有考虑 Windows 7(或更高版本) 的 UAC(用户账户权限控制) 问题的话,我们的程序出现的问题就很容易在我们的测试中暴露出来。事实上,上面的代码也不是一定能通过第一次断言的,我们把构建生成的(Debug 模式的)可执行文件复制到我们的系统盘的 Program Files 文件夹再执行,那么 Win7 及以上的操作系统的UAC都会导致程序无法通过第一次断言的。所以在这种情况下我们就需要在必要的情况申请管理员权限避免程序BUG的发生。

在我们的实际使用过程中,我们需要注意一些使用 assert 的问题。首先我们看看下面的这个断言语句:

//... 
assert( c1 /*条件1*/ && c2 /*条件2*/ );
//...

我们思考一下:如果我们的程序在这里断言失败了,我们如何知道是 c1 断言失败还是 c2 断言失败呢,答案是:没有办法。在这里我们应该遵循使用 assert 函数的第一个原则:每次断言只能检验一个条件,所以上面的代码应该改成这样:

//... 
assert(c1 /*条件1*/); 
assert(c2 /*条件2*/); 
//...

这样,一旦出现问题,我们就可以通过行号知道是哪个条件断言失败了。

接下来我们来思考一个问题:我们可以使用 assert 语句代替我们的条件过滤语句么?我们来举个例子,我们写了一个视频格式转换器,我们本应输出标准MP4格式的视频,但是由于编码解码库的问题,我们在转换过程中出现了错误,像这种情况下,我们能否用 assert 代替掉我们的 if 语句呢(假设这里忽略了 Visual Studio 发布版程序编译过程中自动定义的 NDEBUG 宏)?很明显,这样做是不可以的。这是为什么呢?

现在我们来区分一下程序中的错误与异常,所谓错误,是代码编写途中的缺陷导致的,是程序运行中可以用 if 语句检测出来的。而异常在我们的 C 语言中,一般也可以使用 if 语句判断,并进行对应的处理。而 assert 是用来判断我们程序中的代码级别的错误的。像用户输入错误,调用其他函数库错误,这些问题我们都是可以用 if 语句检测处理的。另一方面,使用 if 语句的程序对用户更友好。

下面我们通过代码展示使用 assert 的另外一个注意意事项,我们新建一个工程,输入如下代码:

我们按 F5 运行调试器,我们会看到这样的情景:


这是正常的,我们按 Shift + F5 终止调试,接下来,我们切换一下编译模式到发布模式:


接下来我们按 Ctrl+F5 不绑定调试器直接运行:


我们看到了一个完全不相同的运行结果,这是为什么呢?其实原因很简单,我们注意这段代码:

assert(i++ <= 100);

我们的条件表达式为 i++ <= 100,这个表达式会更改我们的运行环境(变量i的值),在发布版程序中,所有的 assert 语句都会失效,那么这条语句也就被忽略了,但是我们可以把它改为 i++ ; assert(i <= 100); ,这样程序就能正常运行了。所以请记住:不要使用会改变环境的语句作为断言函数的参数,这可能导致实际运行中出现问题。

最后,我们再来探讨一下,什么时候应该用 assert 语句?一个健壮的程序,都会有30%~50%的错误处理代码,几乎用不上 assert 断言函数,我们应该将 assert 用到那些极少发生的问题下,比如Object* pObject = new Object,返回空指针,这一般都是指针内存分配出错导致的,不是我们可以控制的。这时即使你使用了容错语句,后面的代码也不一定能够正常运行,所以我们也就只能停止运行报错了。


http://chatgpt.dhexx.cn/article/5JCvoj2B.shtml

相关文章

c语言之assert()函数用法总结

1.assert宏的原型定义在<assert.h>中&#xff0c;其作用是如果它的条件返回错误&#xff0c;则终止程序执行。 库函数&#xff1a; assert.h 原型定义&#xff1a; void assert( int expression ); assert的作用是现计算表达式 expression &#xff0c;如果其值为假&…

接私活必备!国外5个顶级程序员接私活网站

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 人生交契无老少&#xff0c;论交何必先同调。 文章目录 PeoplePerHour&#xff1a;薪酬最高的专业自由职业者网站GuruFreeLancerUpworkFiverr 话说程序员这个职业有…

关于网上程序员接私活的问题

点击上方“程序人生”&#xff0c;选择“置顶公众号” 第一时间关注程序猿&#xff08;媛&#xff09;身边的故事 文丨eachfeel 很多人都谈网上接私活这件事&#xff0c;其实大家想法都差不多&#xff0c;现在做软件的那么多&#xff0c;工资也不是那么高了&#xff0c;不像以前…

程序员兼职可以从什么平台接私活?

之前有一项调查&#xff0c;结果显示&#xff1a;想通过副业赚钱的朋友&#xff0c;其中60%的人找不到门路。今天这篇文章就给大家一批可以接私活的平台。不过&#xff0c;再次强调一下&#xff0c;副业并不等于接私活儿。 私活类型与价格区间 程序员兼职的项目大致可分为三类…

10个程序员可以接私活的平台和一些建议!

来源&#xff1a;http://mrw.so/5isQLi 什么样的私活不能接 1、没有第三方担保的个人对个人的尽量不要接&#xff0c;双方都没保障&#xff0c;出了问题很大的可能撕破脸皮不了了之。 2、一上来就直接说给我开发一个什么软件&#xff0c;不说具体需求&#xff0c;没有需求文档的…

程序员接私活常用平台汇总

作者&#xff1a;镇上宝塔 素材来源&#xff1a;今日头条 今天分享一些接私活的常用平台。 ▍前 言 关于程序员接私活&#xff0c;社会各界说法不一。按照作者的观点来说如果你确实急用钱&#xff0c;价格又合适&#xff0c;那就去做。如果不怎么缺钱&#xff0c;那就接私活之前…

程序员接私活的几个平台和建议,避免掉坑!

大家对于程序员接私活这件事的看法&#xff0c;褒贬不一。但是你如果确实用钱&#xff0c;价格又合适&#xff0c;那就大胆去接。 如果不那么缺钱&#xff0c;那么接私活之前先考虑清楚&#xff0c;如果自己将空余时间用在接私活所产生的价值是不是大于提升自己。如果是的话&a…

程序员接私活月入2万?分享10个接私活的网站快收藏~

最近&#xff0c;在和身边的程序员聊天中&#xff0c;听不少朋友分享了自己接私活的经历&#xff0c;那收入真是让我“瞠目结舌” … 程序员A&#xff1a;我Java程序员&#xff0c;工作两年&#xff0c;月薪13K&#xff0c;私活20K。 程序员B&#xff1a;之前在单位上班&#…

推荐几个程序员接私活的网站

相信很多新手程序员&#xff0c;都希望能迅速提高自己的能力同时&#xff0c;又可以赚点外快增加下个人收入&#xff0c;那么&#xff0c;去接一些私活是一个不错的选择。但是接私活之前也要考虑清楚&#xff0c;因为私活一般都会占用自己大量的休息时间&#xff0c;而如果你把…

程序员接私活完整攻略

接私活对程序员这个圈子来说是一个既公开又隐私的话题&#xff0c;不说全部&#xff0c;应该大多数程序员都有过想要接私活的想法&#xff0c;当然&#xff0c;也有部分得道成仙的不主张接私活。但是很少有人在公开场合讨论私活的问题&#xff0c;似乎都在避嫌。就跟有人下班后…

【程序人生】程序员接私活常用平台汇总

00. 目录 文章目录 00. 目录01. 前言02. 程序员客栈03. 码市04. 猪八戒网05. 开源众包06. 智城外包网07. 实现网08. 猿急送09. 人人开发10. 开发邦11. 电鸭社区12. 快码13. 英选14. Upwork15. Freelancer16. Dribbble17. Remoteok18. Toptal19. AngelList20. Topcoder21. 附录 …

程序员们,千万不要接私活!

点击上方“程序员小灰”&#xff0c;选择“置顶公众号” 有趣有内涵的文章第一时间送达&#xff01; 本文转载自公众号 前端你别闹 这个话题很纠结 现在社会&#xff0c;有很多人都在利用个人时间兼职赚钱&#xff0c;程序员俗称“接私活”&#xff0c;其他行业称作兼职&#x…

盘点10个程序员可以接私活的平台和一些建议,赚麻了...

你们当程序员不会都拿着几千、万把块钱的死工资吧&#xff0c;今天为大家分享一些可以接私单的平台&#xff0c;我反正已经赚麻了。 如果你的工作相对没那么费时间&#xff0c;可以空闲的时候去接点私活。或者是还没有找工作之前&#xff0c;可以通过一些平台接一些兼职&#…

程序员一般通过什么途径接私活?怎样做兼职程序员接私活?

国内众包平台和国外众包平台差不多&#xff0c;只不过国外的工程师来自全球&#xff08;当然美欧印居多&#xff09;&#xff0c;业务范围比国内的多一点&#xff0c;具体可以看upwork、freelancer上的介绍&#xff0c;不过国外的合作方式多少有些水土不服&#xff0c;如果接单…

程序员第一次接私活?记住这三点让你事半功倍

不少程序员都有接私活的想法&#xff0c;但恰恰就如开发者之间的论调一样&#xff0c;接私活其实是有一定难度的&#xff0c;想找到合适的单子&#xff0c;顺利地做完并拿到薪水&#xff0c;需要注意的事儿很多&#xff0c;接下来和大家分享一下&#xff0c;程序员第一次接私活…

程序员接私活最最完整攻略

接私活对于程序员这个圈子来说是一个既公开又隐私的话题&#xff0c;当你竭尽全力想要去接私活的时候一定做过这样的事情&#xff0c;百度搜索“程序员如何接私活”、“程序员在哪里接外包”等等问题&#xff0c;今天就送大家最完整攻略&#xff0c;千万别错过了。 做私活挣钱吗…

前端程序员接私活,直呼赚麻了

总有一些前端程序员会想找私活&#xff0c;但是又不清楚具体的办法&#xff0c;或者是做了但没完全做&#xff0c;吃力又不讨好还赚不到钱。今天就给大家介绍一些可行性高的方法&#xff0c;让你快速找到合适的前端兼职。 干货满满&#xff0c;希望大家点赞收藏下&#xff0c;别…

程序员接私活月入2万?分享10个接私活的网站!

最近&#xff0c;播妞在和身边的程序员聊天中&#xff0c;听不少朋友分享了自己接私活的经历&#xff0c;那收入真是让我“瞠目结舌” ...... 程序员A&#xff1a;我Java程序员&#xff0c;工作两年&#xff0c;月薪13K&#xff0c;私活20K。 程序员B&#xff1a;之前在单位上班…

接私活必备的 10 个开源项目!

点击蓝色“GitHubDaily”关注我 加个“星标”&#xff0c;每天下午 18:35&#xff0c;带你逛 GitHub&#xff01; 作者 | SevDot 来源 | http://1t.click/VE8 Web 开发中几乎的平台都需要一个后台管理&#xff0c;但是从零开发一套后台控制面板并不容易&#xff0c;幸运的是有很…

程序员一般都如何接私活,我也想接,有什么可行的方法吗?

二哥&#xff0c;你好&#xff0c;我想知道一般程序猿都如何接私活&#xff0c;我也想接&#xff0c;能告诉我一些方法吗&#xff1f; 上面是一个读者“烦不烦”问我的一个问题。其实不止是“烦不烦”&#xff0c;还有很多读者问过我类似这样的问题。 我接的私活不算多&#x…