Debugging a collision with a CPP macro name

A collision occurs when an identifier is used in a C or C++ program which is accidentally the name a macro definition. It ought not to happen if basic conventions are followed about naming of macros, functions and variables, but inevitably it does occur at some point for most large, long-lived projects.

The errors can be difficult to debug since they are only triggered by an unexpected macro expansion and so do not seem to match the source code used. For example:

#include <limits.h>

struct {
  const int INT_MAX;
} a;

when compiled with GCC 6.3 gives the following error:

preprocerror.c:4:13: error: expected identifier or ‘(’ before numeric constant
   const int INT_MAX;
             ^

A collision error should be suspected when errors appear not to fit into the source file context, especially if they occur after a new header is included or library or system include headers are updated.

With gcc these errors are easily debugged using the "-E" and "-dD" flags. The "-E" stops at the end of pre-processing and outputs the pre-processed input file. For the example above it gives:

/* Some lines removed for clarity! */
# 35 "/usr/lib/gcc/x86_64-redhat-linux/6.3.1/include/limits.h" 2 3 4
# 2 "preprocerror.c" 2

struct {
  const int 0x7fffffff;
} a;

So it can clearly be seen that was intended to be an identifier was expanded to a numeric literal. The root cause of the expansion can be identified with the "-dD" flag, i.e., run "gcc -E -dD". This gives the output:

/* Some lines omitted */

#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
# 96 "/usr/lib/gcc/x86_64-redhat-linux/6.3.1/include/limits.h" 3 4
#undef CHAR_MIN
#define CHAR_MIN SCHAR_MIN
#undef CHAR_MAX
#define CHAR_MAX SCHAR_MAX



#undef SHRT_MIN
#define SHRT_MIN (-SHRT_MAX - 1)
#undef SHRT_MAX
#define SHRT_MAX __SHRT_MAX__


#undef USHRT_MAX



#define USHRT_MAX (SHRT_MAX * 2 + 1)



#undef INT_MIN
#define INT_MIN (-INT_MAX - 1)
#undef INT_MAX
#define INT_MAX __INT_MAX__


/* Some lines omitted */

# 2 "preprocerror.c" 2

struct {
  const int 0x7fffffff;
} a;

In the output we can search for the identifier that was expanded out (INT_MAX in this case) and the pre-processor annotation line preceding it (i.e., the line starting with the hash symbol) gives the header which introduced the macro defintion which caused the expansion. See also it description of the annotations.