When you go back to C/C++ after a week of coding in Python, funny things can happen. I already described such a case in this post.
Recently, I had another surprising incident. I was scanning my code changes in order to find a bug that had pestered me for quite a while. I rubbed my eyes in disbelief when I came across this ‘if’ statement:
1 2 3 4 5 |
if ((sensorIndex >= MAX_SENSORS) and (repeat == REPEAT_CYCLIC)) { ... } |
How could this even compile? Instead of ‘&&’ I inadvertently typed ‘and’, the Python logical ‘and’ operator. At first, I thought that this must either be a g++ extension or some clever guy* had defined
1 2 3 |
#define and && |
somewhere in a header file that I pulled. Being biased towards the second theory, I did an experiment and undefined ‘and’ just before my ‘if’ statement:
1 2 3 |
#undef and |
but it didn’t compile. Luckily, the compiler message that I got from g++ unraveled the mystery:
1 2 3 |
error: "and" cannot be used as a macro name as it is an operator in C++ |
Whoa! ‘and’ is an operator (a token) in C++ that hitherto I’d never heard of. In fact, there’s a whole bunch of what the C++ standard calles “alternative tokens” (or sometimes “alternative representations”):
Alternative Token | Equivalent To |
---|---|
and | && |
and_eq | &= |
bitand | & |
bitor | | |
compl | ~ |
not | ! |
not_eq | != |
or | || |
or_eq | |= |
xor | ^ |
xor_eq | ^= |
It didn’t take long and the feeling of surprise was replaced with a feeling of disappointment. Some of the bit-wise operators have a ‘bit’ prefix while others don’t. ‘and’ and ‘bitand’, for instance, but ‘and_eq’ should actually be ‘bitand_eq’, because ‘&=’ is a bitwise operator — sigh! The same goes for ‘or’, ‘bitor’ and ‘or_eq’. By the same token (pun intended!), ‘xor’ and ‘xor_eq’ should really be ‘bitxor’ and ‘bitxor_eq’, if you’d ask me.
Not so confusing, actually quite beneficial, are the operators ‘and’, ‘or’, and ‘not’ by themselves. Consider:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
if ((i > 0) and (k > 0)) { ... } if ((x == 0) or (y == 0)) { ... } if (not valid) { ... } |
While using these newly discovered keywords is certainly not a huge thing, I do believe that alternative operators are more readable than their cryptic, traditional counterparts. Habitually used, they even avoid classic blunders like forgetting to put a second ‘&’ or ‘|’ in logic expressions. I think I’ll give them a try — but this time as a deliberate act, instead of a Freudian slip like last time.
Note, however, that in C, these alternative representations don’t exist as keywords. Instead, they are defined in iso646.h as macros — just like the “clever guy” would have done it :-)
________________________________
*) Once, such a “clever guy” made fun of our team’s coding standard by defining this macro (the letter O) in a global header file:
#define O (1 – 1)
and using ‘O’ in his code whenever he needed a literal ‘0’ (zero):
for (int i = O; i < max; ++i) {
…
}
When I asked him why on earth he did such an insane thing, he replied, “Well, our coding standard says that we MUST not use octal literals, but 0 is an octal literal since it starts with a ‘0’. Smartass! ↩