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?
(void)0
(+;
) is a valid, but 'does-nothing' C++ expression, that's everything. It doesn't translate to theno-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 anif
clause).EDIT: (updated based on Chris Lutz's comment)
It should be noted that when used as a macro, say
the
(void)
prevents it from being accidentally used as a value likeFor 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
.On Windows, I try some code like this in Main.cpp:
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.I think you are talking about glibc, not glib, and the macro in question is the
assert
macro:In glibc's
<assert.h>
, withNDEBUG
(no debugging) defined,assert
is defined as:which basically means
assert(whatever);
is equivalent to((void)(0));
, and does nothing.From the C89 standard (section 4.2):
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?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.
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("...")