C语言中的assert

C语言中的assert

https://blog.youkuaiyun.com/dacxu/article/details/27313799

assert(expression);

若expression表达式为false,当前进程会调用abort终止运行,并且会向stderr写一条消息。

这条消息根据不同的实现有所不同,但是至少会包括,assert所在的源文件的文件名,行号,及对对应的expression。

另外,若在release状态下,assert宏会被定义为void(0)。

首先介绍宏_CRT_WIDE(_string)

#define __CRT_WIDE(_String) L##_String  
#define _CRT_WIDE(_String) __CRT_WIDE(_String)  

作用是在字符串String前面加上L,变成宽字符串(一个字符两个字节),因为接下来需要调用的函数的参数为w_char类型,两层宏定义用来保证_String也为宏定义时可以展开,##的用法详见https://blog.youkuaiyun.com/xiaoyink/article/details/80211141

assert宏的定义如下:

#ifdef  NDEBUG  
  
    #define assert(_Expression)     ((void)0)  
  
#else  
  
    void _wassert(const wchar_t * _Message, const wchar_t *_File, unsigned _Line);  
    #define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )  
  
#endif   

release状态下会定义NDEBUG宏,此时assert什么也不做。在DEBUGU状态下,assert(_Expression)首先被替换成||表达式。根据||表达式的规则首先计算(!!(_Expression))的值,如果为true,||后面的表达式不会做计算。如果为false,将会计算后面的表达式。然而,后面的表达式是一个_wassert函数调用,对应的参数为_Expression对应的字符串,assert所在的文件名,及行号,_CRT_WIDE(#_Expression),#_Expression将_Expression其转化成字符串,然后转化成宽字符串传入_wassert()函数。

mingw的_wassert函数实现如下:

extern int mingw_app_type;  
      
void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line)  
{  
    wchar_t *msgbuf = (wchar_t *) malloc (8192*sizeof(wchar_t));  
  
    if (!_File || _File[0] == 0)  
        _File = L"<unknown>";  
  
    if (!_Message || _Message[0] == 0)  
        _Message = L"?";  
  
    _snwprintf (msgbuf, 8191,  
        L"Assertion failed!\n\nFile: %ws, Line %u\n\nExpression: %ws",  
        _File,_Line, _Message);  
  
    if (mingw_app_type == 0)  
        fwprintf (stderr, L"%ws\n", msgbuf);  
    else  
        OutputDebugStringW(msgbuf);  
  
    abort ();  
}  
显然,上面的实现不难。msbuf中存放的就是要打印的输出。根据不同的app类型,输出方式不一样。如果是普通的命令行方式,输出到stderr。如果是图形应用,估计会跳出一个窗口吧!程序最后会调用一个abort,结束程序。当然,进程都结束了,msbuf会自动释放,没必要手工释放了。
在 C 语言中,`assert` 是一个用于调试的宏,定义在 `<assert.h>` 头文件中。它的主要作用是帮助程序员在调试过程中检测程序中的逻辑错误(即假设是否成立)。如果假设不成立(即表达式为假),`assert` 会终止程序的执行,并输出一条错误信息,包括文件名、行号以及导致失败的表达式。 ### 使用方式: ```c #include <assert.h> assert(表达式); ``` 如果表达式的结果为 `0`(即为假),则 `assert` 会打印错误信息并调用 `abort()` 函数终止程序。如果表达式为非零值(即为真),则程序继续执行。 --- ### 示例代码: ```c #include <stdio.h> #include <assert.h> int divide(int a, int b) { assert(b != 0); // 确保除数不为0 return a / b; } int main() { int result = divide(10, 2); printf("Result: %d\n", result); // 下面这行将触发 assert 失败 result = divide(10, 0); return 0; } ``` --- ### 输出(当触发断言失败时): ``` Assertion failed: b != 0, file example.c, line 6 Aborted (core dumped) ``` --- ### 注意事项: 1. **只在调试阶段使用**:`assert` 主要用于开发和调试阶段,用于捕捉不应该发生的错误。在发布版本中,可以通过定义 `NDEBUG` 宏来禁用所有 `assert` 检查。 ```c #define NDEBUG #include <assert.h> ``` 2. **不要用于处理正常错误**:`assert` 不应该用来处理程序运行时的正常错误(如用户输入错误、文件不存在等),而应该用于捕捉程序内部逻辑错误。 3. **不可替代正式错误处理机制**:`assert` 不能替代正式的错误处理机制,因为它在发布版本中可以被完全禁用。 --- ### 相关问题: 1. 如何在发布版本中禁用 assert? 2. assert 和 errno 的区别是什么? 3. assert 是否可以用于检查函数参数的有效性? 4. 如何自定义 assert 的行为?
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值