Macros with halos

2008-09-02, , Comments

Slippery beast

The C preprocessor is a notoriously primitive and slippery creature. Included and occasionally embraced by C++, it may eventually prove to be the downfall of the newer language. How much trouble has been caused by seemingly innocuous definitions?

#define min(a, b) (((a) < (b)) ? (a) : (b))

This macro hobbles any attempt to use the standard C++ algorithm, std::min(), and since it’s a preprocessor thing the compiler warnings may not alert you immediately to what’s going on. You don’t have to include <algorithm> directly to trigger the problem.

Try compiling this stripped down source file using GCC 3.4.6:

macro.cpp
#include <string>
#define min(a, b)  (((a) < (b)) ? (a) : (b)) 
#include <sstream>

and you’ll see something like:

In file included from /usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/streambuf:781,
                 from /usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/ios:50,
                 from /usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/istream:45,
                 from /usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/sstream:45,
                 from macros.cpp:3:
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/streambuf.tcc: In member function `virtual std::streamsize std::basic_streambuf<_CharT, _Traits>::xsgetn(_CharT*, std::streamsize)':
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/streambuf.tcc:54: error: expected unqualified-id before '(' token
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/streambuf.tcc: In member function `virtual std::streamsize std::basic_streambuf<_CharT, _Traits>::xsputn(const _CharT*, std::streamsize)':
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/streambuf.tcc:88: error: expected unqualified-id before '(' token

I spent a while tracking down a similar problem today (needless to say, the offending macro was hiding several #includes away from the file which triggered the error1). Once I’d exposed the source, I naturally wanted to grumble to someone, so I pasted the code into an instant message to a colleague. Look, my messaging client sanctified the macro by adding halos to the a’s!

Macros with Halos


1 One tip for tracking down such problems is to run the preprocessing phase of compilation on its own: with GCC, for example, supply the -E flag.