自定义 C++ 断言宏 [英] Custom C++ assert macro

查看:31
本文介绍了自定义 C++ 断言宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了一篇内容丰富的文章:http://cnicholson.net/2009/02/stupid-c-tr​​icks-adventures-in-assert/它指出了我当前的调试宏套件中存在的大量问题.

I stumbled upon an informative article: http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ which pointed out a great number of problems that exist in my current suite of debugging macros.

如果您点击链接,将在文章末尾附近提供宏最终版本的完整代码.

The full code for the final version of the macro is given near the end of the article if you follow the link.

呈现的一般形式是这样的(如果我转错了,请有人纠正我):

The general form as presented is like this (somebody please correct me if i am wrong in transposing it):

#ifdef DEBUG
#define ASSERT(cond)   
    do   
    {   
        if (!(cond))   
        {   
            ReportFailure(#cond, __FILE__, __LINE__, 0); 
            HALT(); 
        }   
    } while(0)  
#else  
#define ASSERT(cond)   
    do { (void)sizeof(cond); } while(0) 

在考虑用我学到的东西修改我的代码时,我注意到那篇文章的评论中有几个有趣的变化:

While thinking about modifying my code with what I have learned, I noticed a couple of interesting variations posted in the comments for that article:

一个是你不能将这个宏与三元运算符一起使用(即 cond?ASSERT(x):func()),建议替换 if() 带有三元运算符和一些括号以及逗号运算符.后来另一位评论者提供了这个:

One was that you cannot use this macro with the ternary operator (i.e. cond?ASSERT(x):func()), and the suggestion was to replace the if() with the ternary operator and some parentheses as well as the comma operator. Later on another commenter provided this:

#ifdef DEBUG
#define ASSERT(x) ((void)(!(x) && assert_handler(#x, __FILE__, __LINE__) && (HALT(), 1)))
#else
#define ASSERT(x) ((void)sizeof(x))
#endif

我认为在这种情况下使用逻辑和 && 特别聪明,在我看来,这个版本比使用 if 的版本更灵活甚至三元 ?:.更好的是,assert_handler 的返回值可用于确定程序是否应该停止.虽然我不确定为什么它是 (HALT(), 1) 而不是 HALT().

I thought the use of logical and && is particularly smart in this case and it seems to me that this version is more flexible than one using the if or even the ternary ?:. Even nicer is that the return value of assert_handler can be used to determine if the program should halt. Although I am not sure why it is (HALT(), 1) instead of just HALT().

这里的第二个版本是否有任何我忽略的特别缺点?它取消了包裹在宏周围的 do{ } while(0),但这里似乎没有必要,因为我们不需要处理 ifs.

Are there any particular shortcomings with the second version here that I have overlooked? It does away with the do{ } while(0) wrapped around the macros but it seems to be unnecessary here because we don't need to deal with ifs.

你怎么看?

推荐答案

在 C 和 C++ 标准库中,assert 是一个需要充当函数的宏.该要求的一部分是用户必须能够在表达式中使用它.例如,使用标准的 assert 我可以做到

In C and C++ standard library, assert is a macro that is required to act as a function. A part of that requirement is that users must be able to use it in expressions. For example, with standard assert I can do

int sum = (assert(a > 0), a) + (assert(b < 0), b);

在功能上与

assert(a > 0 && b < 0)
int sum = a + b;

尽管前者可能不是编写表达式的好方法,但该技巧在许多更合适的情况下仍然非常有用.

Even though the former might not be a very good way to write an expression, the trick is still very useful in many more appropriate cases.

这立即意味着,如果您希望自己的自定义 ASSERT 宏模仿标准的 assert 行为和可用性,则使用 ifASSERT 的定义中的 >do { } while (0) 是不可能的.一种仅限于这种情况下的表达式,这意味着使用 ?: 运算符或短路逻辑运算符.

This immediately means that if one wants their own custom ASSERT macro to mimic standard assert behavior and usability, then using if or do { } while (0) in the definition of ASSERT is out of question. One is limited to expressions in that case, meaning using either ?: operator or short-circuiting logical operators.

当然,如果你不关心制作一个标准的自定义ASSERT,那么你可以使用任何东西,包括if.链接的文章似乎甚至没有考虑这个问题,这很奇怪.在我看来,类函数的 assert 宏肯定比非类函数的更有用.

Of course, if one doesn't care about making a standard-like custom ASSERT, then one can use anything, including if. The linked article doesn't even seem to consider this issue, which is rather strange. In my opinion, a function-like assert macro is definitely more useful than a non-function-like one.

至于 (HALT(), 1)... 这样做是因为 && 操作符需要一个有效的参数.HALT() 的返回值可能不代表 && 的有效参数.据我所知,它可能是 void,这意味着仅仅 HALT() 根本不会编译为 &&.(HALT(), 1) 始终计算为 1 并且具有类型 int,它始终是 & 的有效参数.&.因此,无论 HALT() 的类型如何,(HALT(), 1) 始终是 && 的有效参数.

As for the (HALT(), 1)... It is done that way because && operator requires a valid argument. The return value of HALT() might not represent a valid argument for &&. It could be void for what I know, which means that a mere HALT() simply won't compile as an argument of &&. The (HALT(), 1) always evaluates to 1 and has type int, which is always a valid argument for &&. So, (HALT(), 1) is always a valid argument for && regardless of the type of HALT().

您对 do{ } while(0) 的最后评论似乎没有多大意义.将宏封装到 do{} while(0) 的目的是处理外部的 if,而不是宏内部的 if定义.您总是必须处理外部if,因为您的宏总是有可能在外部if 中使用.在后一个定义中,不需要 do{} while(0),因为该宏是一个 表达式.而且作为一个表达式,它已经自然没有外部ifs的问题.所以,没有必要对它们做任何事情.此外,正如我上面所说的,将它包含在 do{ } while(0) 中会完全违背它的目的,将它变成一个非表达式.

Your last comment about do{ } while(0) does not seem to make much sense. The point of enclosing a macro into do{ } while(0) is to deal with external ifs, not the ifs inside the macro definition. You always have to deal with external ifs, since there's always a chance that your macro will be used in an external if. In the latter definition do{ } while(0) is not needed because that macro is an expression. And being an expression, it already naturally has no problems with external ifs. So, there's no need to do anything about them. Moreover, as I said above, enclosing it into do{ } while(0) would completely defeat its purpose, turning it into a non-expression.

这篇关于自定义 C++ 断言宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆