59

I have seen debug printfs in glibc which internally is defined as (void) 0, if NDEBUG is defined. Likewise the __noop for Visual C++ compiler is there too. The former works on both GCC and VC++ compilers, while the latter only on VC++. Now we all know that both the above statements will be treated as no operation and no respective code will be generated; but here's where I've a doubt.

In case of __noop, MSDN says that it's a intrinsic function provided by the compiler. Coming to (void) 0 ~ Why is it interpreted by the compilers as no op? Is it a tricky usage of the C language or does the standard say something about it explicity? Or even that is something to do with the compiler implementation?

TylerH
  • 20,799
  • 66
  • 75
  • 101
legends2k
  • 31,634
  • 25
  • 118
  • 222
  • 2
    By just giving `0;` as a statement, I don't get warnings or errors, and I am sure it'll not do any effictive operation and is equal to a no op; Even if so, why type cast it to void? Also, in case of the `#define dbgprintf (void) 0`, when it's called like `dbgprintf("Hello World!");` -> `(void) 0("Hello World!");` - what does it mean? – legends2k Feb 04 '10 at 10:41
  • 5
    this should probably be `#define dbgprintf(x) (void)0;` though I found `#define dbgprintf(x)` perfectly sufficient. I think the cast to void is to remove any return value, so if it is used in context that requires value (and should not), it will cause an error/warning, instead of passing silently. – SF. Feb 04 '10 at 10:48
  • Yea, I didn't notice that the #define ignore param (x) and just does a `(void) 0`. Thanks for pointing it out :) – legends2k Feb 04 '10 at 11:12
  • Well, imagine you are a compiler. What code would you generate for this statement:`(void) 0;`? Now you know. – Kuba hasn't forgotten Monica Nov 19 '13 at 19:03
  • @KubaOber: Haha.. true, I was asking more about the specifics on the typecast, in a language laweryese way ;) – legends2k Nov 20 '13 at 07:32
  • 1
    Why not use ```#define dbgprintf ``` instead of ```#define dbgprintf ((void) 0)``` ??? @legends2k Is there a reason? – AntiMoron Oct 19 '15 at 07:52
  • 2
    @AntiMoron The question is more centered on what does `((void) 0)` mean. Not how to define a no-op macro. – legends2k Oct 19 '15 at 13:52
  • Of course I know that. Just curious about. For ```(void)0``` needs more typing. – AntiMoron Oct 19 '15 at 17:05

5 Answers5

81

(void)0 (+;) is a valid, but 'does-nothing' C++ expression, that's everything. It doesn't translate to the no-op instruction of the target architecture, it's just an empty statement as placeholder whenever the language expects a complete statement (for example as target for a jump label, or in the body of an if clause).

From Chris Lutz's comment:

It should be noted that, when used as a macro (say, #define noop ((void)0)), the (void) prevents it from being accidentally used as a value (like in int x = noop;).

For the above expression the compiler will rightly flag it as an invalid operation. GCC spits error: void value not ignored as it ought to be and VC++ barks 'void' illegal with all types.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
12

Any expression that doesn't have any side-effects can be treated as a no-op by the compiler, which dosn't have to generate any code for it (though it may). It so happens that casting and then not using the result of the cast is easy for the compiler (and humans) to see as not having side-effects.

4

I think you are talking about glibc, not glib, and the macro in question is the assert macro:

In glibc's <assert.h>, with NDEBUG (no debugging) defined, assert is defined as:

#ifdef NDEBUG
#if defined __cplusplus && __GNUC_PREREQ (2,95)
# define __ASSERT_VOID_CAST static_cast<void>
#else
# define __ASSERT_VOID_CAST (void)
#endif
# define assert(expr)           (__ASSERT_VOID_CAST (0))
#else
/* more code */
#endif

which basically means assert(whatever); is equivalent to ((void)(0));, and does nothing.

From the C89 standard (section 4.2):

The header <assert.h> defines the assert macro and refers to another macro,

NDEBUG

which is not defined by <assert.h>. If NDEBUG is defined as a macro name at the point in the source file where <assert.h> is included, the assert macro is defined simply as

#define assert(ignore) ((void)0)

I don't think defining a debug print macro to be equal to (void)0 makes much sense. Can you show us where that is done?

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
  • Yeah, it's glibc and not glib, thanks for notifying; corrected it in the question. – legends2k Feb 04 '10 at 11:16
  • http://doc.ddart.net/msdn/header/include/assert.h.html - This is one of the many *assert.h*s I've seen with `(void) 0`. – legends2k Feb 04 '10 at 11:19
  • 1
    @legends2k: `assert(expr);` is not a debug printing macro. My answer above answers your question about `assert()`. – Alok Singhal Feb 04 '10 at 11:20
  • I agree, it's assert. But the whole doubt was to know more about the `(void) 0` in general as no operation, based on the language or compiler constructs. Thanks! – legends2k Feb 04 '10 at 11:28
1

Even if so, why type cast it to void? Also, in case of the #define dbgprintf (void) 0, when it's called like dbgprintf("Hello World!"); -> (void) 0("Hello World!"); - what does it mean?

Macros replace your code with something else, so if you #defined dbgprint (that accepts x) as

void (0)

then no rewriting of X will occur in replacement, so dbgprintf("Helloworld") will not be converted to (void) 0("Hello world"), but to (void) 0; - not only macro name dbgprint is replaced by (void) 0, but the whole call dbgprintf("...")

TylerH
  • 20,799
  • 66
  • 75
  • 101
Darko Maksimovic
  • 1,155
  • 12
  • 14
0

On Windows, I try some code like this in Main.cpp:

#include <iostream>
#define TRACE ((void)0)
int main() {
  TRACE("joke");
  std::cout << "ok" << std::endl;
  return 0;
}

Then, I build the Release version exe file with Main.i output. In Main.i file, the TRACE macro was replaced to:((void)0)("joke"), and visual studio give an warning:"warning C4353: nonstandard extension used: constant 0 as function expression.

Use '__noop' function intrinsic instead".

Run the exe file, console print out "ok" characters.

So I think all is clear: the definition of macro TRACE[#define TRACE ((void)0)] is illegal according to c++ syntax, but c++ compiler of visual studio supports this behavior as a compiler extension.

So my conclusion is: [#define TRACE ((void)0)] is illegal c++ statement, and you at best DO NOT use this. But [#define TRACE(x) ((void)0)] is legal statement. That's all.

TylerH
  • 20,799
  • 66
  • 75
  • 101