Custom C++ assert macro

寵の児 提交于 2019-11-28 16:52:28

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);

which is functionally the same as

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.

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.

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.

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().

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.

For the sake of completeness, I published a drop-in 2 files assert macro implementation in C++:

#include <pempek_assert.h>

int main()
{
  float min = 0.0f;
  float max = 1.0f;
  float v = 2.0f;
  PEMPEK_ASSERT(v > min && v < max,
                "invalid value: %f, must be between %f and %f", v, min, max);

  return 0;
}

Will prompt you with:

Assertion 'v > min && v < max' failed (DEBUG)
  in file e.cpp, line 8
  function: int main()
  with message: invalid value: 2.000000, must be between 0.000000 and 1.000000

Press (I)gnore / Ignore (F)orever / Ignore (A)ll / (D)ebug / A(b)ort:

Where

  • (I)gnore: ignore the current assertion
  • Ignore (F)orever: remember the file and line where the assertion fired and ignore it for the remaining execution of the program
  • Ignore (A)ll: ignore all remaining assertions (all files and lines)
  • (D)ebug: break into the debugger if attached, otherwise abort() (on Windows, the system will prompt the user to attach a debugger)
  • A(b)ort: call abort() immediately

You can find out more about it there:

Hope that helps.

Although I am not sure why it is (HALT(), 1) instead of just HALT().

I imagine HALT may be a macro (or other stand-in name) for exit. Say we wanted to use exit(1) for our HALT command. exit returns void, which cannot be evaluated as the second argument to &&. If you use the comma operator, which evaluates its first argument, then evaluates and returns the value of it's second argument, we have an integer (1) to return to &&, even though we never reach that point because HALT() will cause us to stop long before then.

Basically, any function that fills in for HALT is probably going to have a return value of void, because it would make no sense for it to return any value. We could make it return an int, just for the sake of the macro, but if we're already hacking around with a macro a little more hackery can't hurt, can it?

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!