locked
Why does the assert macro has to expand to `((void)0)` in a release build? RRS feed

  • Question

  • In the picture below you can see (in the Output window) that the macro assert was expanded in a release build, as `((void)0)`. This is in accordance with the definition of the assert macro in <assert.h>, as can be seen in the right portion of the picture. The red squiggles in the picture are probably a bug from Intellisense, as the code compiles without a problem. 

    Figure 1

    To show that the assert macro definition in a release build does not necessarily has to expand to `(void(0))` I made a copy of the file assert.h in the library to the project directory with a small change: I erased the `(void(0))` from the macro definition. You can see this in the right portion of the next picture below. I then compiled the code with #include "assert.h" in place of #include <assert.h> used previously. You can see that the macro expansion in the Output window changed from `((void)0)` to nothing, and the code also compiled correctly without any problem.

    Then, why does the assert macro has to expand to `((void)0)` in a release build?

    Tuesday, May 5, 2020 2:41 PM

Answers

  • Your version would get a syntax error in (admittedly contrived) cases like

    DoSomething(), assert("Good");


    Igor Tandetnik

    • Marked as answer by Belloc Tuesday, May 5, 2020 6:31 PM
    Tuesday, May 5, 2020 5:31 PM
  • My guess would be, to prevent nonsensical code from compiling. E.g.

    int x = f(),
    assert(x);

    Here, I accidentally typed a comma where I meant a semicolon. With ((void)0) this would fail to compile. With 0, this would succeed and silently change the meaning.


    Igor Tandetnik

    • Marked as answer by Belloc Monday, May 11, 2020 1:47 PM
    Sunday, May 10, 2020 9:32 PM
  • Also remember that while the expression is more complicated, the same thing happens for the debug definition of assert.

    #define assert(expression) (void)(                                                       \
        (!!(expression)) ||                                                              \
        (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
    )

    The void is there for the reason Igor guesses, basically, it stops these macros from being used when they shouldn't. You should think of these as functions with a void return type.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Marked as answer by Belloc Monday, May 11, 2020 1:51 PM
    Monday, May 11, 2020 8:54 AM

All replies

  • I didn't check references, but it appears to be Standards requirement.

    See https://stackoverflow.com/questions/56268229/why-does-assert-macro-have-value-even-with-ndebug

    Tuesday, May 5, 2020 3:01 PM
  • Your version would get a syntax error in (admittedly contrived) cases like

    DoSomething(), assert("Good");


    Igor Tandetnik

    • Marked as answer by Belloc Tuesday, May 5, 2020 6:31 PM
    Tuesday, May 5, 2020 5:31 PM
  • Brilliant. Thank you.

    But why can't it be just

    #define assert(expression) 0

    instead of

    #define assert(expression) ((void)0)

    • Edited by Belloc Tuesday, May 5, 2020 6:35 PM
    Tuesday, May 5, 2020 6:31 PM
  • This answers my last question on my previous post.

    GCC emits the warning "statement has no effect" for any replacement-list different than `(void(0))` in the directive

    #define assert(expression) ((void)0)

    In this answer in SO the OP says: "When you ignore something which is nothing, it is not considered a problem by GCC--and with good reason, since casting to void is an idiomatic way to ignore a variable explicitly in C and C++.."

    As you can see here, GCC emits the warning mentioned above, when the `assert` is defined with `0` instead of `((void)0)`.


      
    Sunday, May 10, 2020 8:03 PM
  • My guess would be, to prevent nonsensical code from compiling. E.g.

    int x = f(),
    assert(x);

    Here, I accidentally typed a comma where I meant a semicolon. With ((void)0) this would fail to compile. With 0, this would succeed and silently change the meaning.


    Igor Tandetnik

    • Marked as answer by Belloc Monday, May 11, 2020 1:47 PM
    Sunday, May 10, 2020 9:32 PM
  • Also remember that while the expression is more complicated, the same thing happens for the debug definition of assert.

    #define assert(expression) (void)(                                                       \
        (!!(expression)) ||                                                              \
        (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
    )

    The void is there for the reason Igor guesses, basically, it stops these macros from being used when they shouldn't. You should think of these as functions with a void return type.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Marked as answer by Belloc Monday, May 11, 2020 1:51 PM
    Monday, May 11, 2020 8:54 AM
  • My guess would be, to prevent nonsensical code from compiling. E.g.

    int x = f(),
    assert(x);

    Here, I accidentally typed a comma where I meant a semicolon. With ((void)0) this would fail to compile. With 0, this would succeed and silently change the meaning.


    Igor Tandetnik

    Yes you are right. This is the correct answer, but you don't need the comma in the example. An initialization like

    int x = assert(x);
    would behave the same way, i.e., it would correctly fail to compile with `(void(0))`, but it would incorrectly succeed with `0`.

    Monday, May 11, 2020 1:46 PM
  • @Darren Rowe

    Absolutely right!

    • Edited by Belloc Monday, May 11, 2020 1:53 PM
    Monday, May 11, 2020 1:51 PM