Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incrementing Preprocessor Macros

I'm trying to make a simple preprocessor loop. (I realize this is a horrible idea, but oh well.)

// Preprocessor.h

#ifndef PREPROCESSOR_LOOP_ITERATION

#define MAX_LOOP_ITERATION 16 // This can be changed.

#define PREPROCESSOR_LOOP_ITERATION 0

#endif

#if (PREPROCESSOR_LOOP_ITERATION < MAX_LOOP_ITERATION)
#define PREPROCESSOR_LOOP_ITERATION (PREPROCESSOR_LOOP_ITERATION + 1) // Increment PREPROCESSOR_LOOP_ITERATION.
#include "Preprocessor.h"
#endif

The issue is that it doesn't look like PREPROCESSOR_LOOP_ITERATION is being incremented, so it just keeps including itself infinitely. If I change the line to an actual integer (like 17), the preprocessor skips over the #include directive properly.

What am I doing incorrectly?

like image 556
Maxpm Avatar asked Apr 25 '26 17:04

Maxpm


1 Answers

The "problem" is that macros are lazily evaluated. Consider your macro definition:

#define PREPROCESSOR_LOOP_ITERATION (PREPROCESSOR_LOOP_ITERATION + 1)

This defines a macro named PREPROCESSOR_LOOP_ITERATION and its replacement list is the sequence of five preprocessing tokens (, PREPROCESSOR_LOOP_ITERATION, +, 1, and ). The macro is not expanded in the replacement list when the macro is defined. Macro replacement only takes place when you invoke the macro. Consider a simpler example:

#define A X
#define B A

B // this expands to the token X

#undef A
#define A Y
B // this expands to the token Y

There is an additional rule that if the name of a macro being replaced is encountered in a replacement list, it is not treated as a macro and thus is not replaced (this effectively prohibits recursion during macro replacement). So, in your case, any time you invoke the PREPROCESSOR_LOOP_ITERATION macro, it gets replaced with

( PREPROCESSOR_LOOP_ITERATION + 1 )

then macro replacement stops and preprocessing continues with the next token.

You can perform limited arithmetic with the preprocessor by defining a sequence of macros and making use of the concatenation (##) operator, but it's quite tedious. You should consider using the Boost.Preprocessor library to help you with this. It will work with both C and C++ code. It allows for limited iteration, but what it does allow is extraordinarily useful. The closest feature that matches your use case is likely BOOST_PP_ITERATE. Other facilities like the sequence (BOOST_PP_SEQ) handlers are very helpful for writing generative code.

like image 154
James McNellis Avatar answered Apr 27 '26 09:04

James McNellis