Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would one use MACRO+0 !=0

Tags:

c++

c

In my current codebase I see this following pattern:

#if SOMETHING_SUPPORTED+0 != 0 ... #endif 

Unfortunately this is a very old codebase and nobody knows how and why it started. I think it started in C and it was slowly converted into C with classes and now it tends to C++

I can't see any obvious advantage of using previous construct instead of the "classic", but maybe I'm missing something:

#if SOMETHING_SUPPORTED ... #endif 

Do you know why would one use #if MACRO+0 != 0 instead of #if MACRO?

like image 583
Mircea Ispas Avatar asked May 05 '16 10:05

Mircea Ispas


People also ask

Why do people use do while 0?

You may see a do loop with the conditional expression set to a constant value of zero (0). This creates a loop that will execute exactly one time. This is a coding idiom that allows a multi-line macro to be used anywhere that a single statement can be used.

Why macros should not be used?

"Using macros can reduce the readability of your code. When you use them, you're basically creating a set of nonstandard language features."

Why do we use macro?

Macros are used to make a sequence of computing instructions available to the programmer as a single program statement, making the programming task less tedious and less error-prone. (Thus, they are called "macros" because a "big" block of code can be expanded from a "small" sequence of characters.)

Why do we need macros in C++?

So, macros not only make names shorter, and infact typedefs and ref alias can also be used to make names shorter, but macros can also avoid runtime overheads. Macros happen way before runtime. Macros have been avoiding run time over heads way before CPP features such as move and template.


1 Answers

The clue here is that the code base is very old.

This trick likely exists because the code once had been ported to a compiler with some very old preprocessor which doesn't treat undefined macros as 0 in preprocessor #if conditionals.

That is to say, as of 1989 ANSI C it was standardized that if we have:

#if foo + bar - xyzzy

the directive is subject to macro replacement, so that if foo, bar or xyzzy are macros, they are replaced. Then any remaining identifiers which were not replaced are replaced with 0. So if foo is defined as 42, but bar and xyzzy are not defined at all, we get:

#if 42 + 0 - 0 

and not, say, bad syntax:

#if 42 + - 

or some other behavior, like diagnostics about bar not being defined.

On a preprocessor where undefined macros are treated as blanks, #if SOMETHING_SUPPORTED expands to just #if, which is then erroneous.

This is the only way in which this IDENT+0 trick makes any real sense. You simply wouldn't ever want to do this if you can rely on preprocessing being ISO C conforming.

The reason is that if SOMETHING_SUPPORTED is expected to have numeric values, it is erroneously scatter-brained to define it as simply a blank. You ideally want to detect when this has happened and stop the compilation with a diagnostic.

Secondly, if you do support such a scatter-brained usage, you almost certainly want an explicitly defined, but blank symbol to behave as if it had the value 1, not the value 0. Otherwise, you're creating a trap. Someone might do this on the compiler command line:

 -DSOMETHING_SUPPORTED=$SHELL_VAR  # oops, SHELL_VAR expanded to nothing 

or in code:

 #define SOMETHING_SUPPORTED  /* oops, forgot "1" */ 

Nobody is going to add a #define or -D for a symbol with the intent of turning off the feature that it controls! The programmer who inserts a #define SOMETHING_SUPPORTED without the 1 will be surprised by the behavior of

 #if SOMETHING_SUPPORTED+0 

which skips the material which was intended to be enabled.

This is why I suspect that few C programmers reading this have ever seen such a usage, and why I suspect that it's just a workaround for preprocessor behavior whose intended effect is to skip the block if SOMETHING_SUPPORTED is missing. The fact that it lays a "programmer trap" is just a side-effect of the workaround.

To work around such a preprocessor issue without creating a programmer trap is to have, somewhere early in the translation unit, this:

#ifndef SOMETHING_SUPPORTED #define SOMETHING_SUPPORTED 0 #endif 

and then elsewhere just use #if SOMETHING_SUPPORTED. Maybe that approach didn't occur to the original programmer, or perhaps that programmer thought that +0 trick was neat, and placed value on its self-containment.

like image 160
Kaz Avatar answered Oct 16 '22 22:10

Kaz