19 comments

[ 3.2 ms ] story [ 52.5 ms ] thread
Well, yes. This is why preprocessor macros should have obvious, inconvenient naming conventions. And should be avoided in favor of more modern (better-behaved) features when possible.
I removed as much macro usage as practical from my ancient C code. Makes the code a lot easier to deal with.
Before #define ing MY_MACRO, do

#ifdef MY_MACRO

#error

#endif

edit: and #undef MY_MACRO after done using it, ideally.

Not a perfect defense either. If you ever have the misfortune of using mentor graphics code, they #define REGISTER. They also ship a standard library that uses the register keyword. If you build a project using their standard library and their toolchain together, it explodes. If you name something like set_register, it also explodes.
Pro tip: `#pragma GCC poison` is very good for (incrementally) getting rid of specific C-isms (both individual macros and individual functions) and keeping them out. It looks like `#pragma deprecated` is similar for MSVC, but it has the major downside of only being a warning.

That said, I am not at all afraid of using macros when appropriate. Just give them names that scream "I_AM_A_MACRO" unless you take care to make them sufficiently function-like, and if public give them a "namespace" prefix either way.

Ugh... I had something similar recently but much more painful to figure out - apparently googletest defines and and or (lowercase) as macros).

I started using googletest in a project with a moderate amount of inline assembly, and of course I got some thoroughly confusing error messages after the substitution replaced the and and or opcodes.

Anyway, I didn't know that push_macro and pop_macro existed, so I'll have to revisit my previous hack around that issue.

In C++ they're alternative tokens and should be keywords, so maybe googletest is providing them as macros as workaround for a compile that didn't support this?

In other words, maybe a computer flag would allow you to disable them being defined?

Although this could result in other issues...

Yeah I kind of thought it was something like that, but searching for such broad terms got me nowhere, and the googletest documentation wasn't good enough for me to find it.
That's standard if `<iso646.h>` is included in C, but said header is a nop for C++.

In the GCC world, inline asm uses strings so macros don't cause problems.

Yeah okay - this was an MSVC project with inline assembly.
Wait what? This is an blogpost from Chen? I did remember reading better quality content before. This is the usual nightmare dealing with larger C++ codebase.
> Doesn’t the non-macro version have a use-after-free?

>

> > Indeed it does. Rats.

Not even the great Raymond Chen writes CVE free code.

as the song goes “… sometimes you are the windshield, and sometimes you are the bug…”
You can suppress function like macros by using parenthesis because function like macro expansion is literally defined as "name directly followed by open paren".

  #define foo(x) something
  void foo(int a) {} // doesn't work
  void (foo)(int a) {} // does work because 'foo)' can never be a function macro
The error is coming from a WinRT header, not something they can easily control. It's similar to having something like `#define string(x) something` and then including <string>.
I knew this would be a preprocessor macro from the second I saw 'nonsensical errors'. The joys of having a multi-decade career in C++ and C.
This is the sort of reason why macros are evil and I hate them. Harder to inspect while running, can't be scoped properly, often have poor names, not as much static/compiler safety measures, etc.

Evil evil evil. I get that sometimes they're unavoidable, but IMO you need to do everything you can to avoid them in C or C++. So many better options. Functions. Lambdas. Templated functions. ANYTHING but macros.

One heinous example is many implementations of '_FORTIFY_SOURCE', unless you want to resort to using lots of clang '__attribute__((__enable_if__(...)))' statements in your inline functions.
One thing I really enjoyed about Rust that I didn't imagine I would-- good compiler error messages. I actually find the compiler to be helpful, which shouldn't be surprising but it is.