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

查看:263
本文介绍了自定义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)包裹宏,但是在这里似乎没有必要,因为我们不需要处理

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 宏来模仿标准 do {} while(0) assert code>在 ASSERT 的定义是没有问题的。在这种情况下,限制为表达式,意味着使用?:运算符或短路逻辑运算符。

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(),1)始终是&& 的有效参数, HALT()

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)中的点是处理外部如果 s,而不是 if s在宏定义内。您总是必须处理外部如果,因为总是有一个机会你的宏将被用于外部 if 。在后面的定义 do {} while(0)不需要,因为这个宏是一个表达式。作为一个表达式,它自然没有问题与外部如果。所以,没有必要做任何事情。此外,如上所述,将它包含到 do {} while(0)将完全击败其目的,将其转换为非表达式。

Your last comment about do{ } while(0) does not seem to make such 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天全站免登陆