How can I write a for
/while
loop inside a #define
directive in C?
-
6Do you think that's a good idea? What's wrong with a short function? For instance, a function won't have to leak an iteration variable into the scopes that use it... – Apr 22 '11 at 20:42
-
@delnan: While I agree that functions should be preferred to macros in almost all cases, a for loop's declaration (the first part) is required to not be leaked outside. – Thomas Edleson Apr 22 '11 at 20:47
-
3@Thomas Edleson: Thinking about it, yes, you're right. Even in older language versions where you can't do `for (int i = 0; ...)`, wrapping it in `do { } while (0)` creates a new scope anyway. – Apr 22 '11 at 20:52
-
@delnan: Why not just wrap it in `{...}`; the `do/while` is superfluous. – Lawrence Dol Apr 22 '11 at 20:57
-
2@Software Monkey: See http://stackoverflow.com/questions/154136/why-are-there-sometimes-meaningless-do-while-and-if-else-statements-in-c-c-macr – Apr 22 '11 at 21:02
-
@delnan: Ahhh. Forgot about that particular wrinkle with C - I knew there were good reasons why we require all if/else clauses to use braces - this would be one of them. – Lawrence Dol Apr 22 '11 at 21:11
6 Answers
You're probably looking for \
to continue a macro definition across several lines:
#define LOOP(start, end) \
for (int i = (start); i < (end); i++) { \
printf("%d\n", i); \
}

- 2,175
- 1
- 16
- 19

- 733,204
- 149
- 1,241
- 1,454
Short answer is "don't". But if you have to, for the love of all that's sacred don't do this:
#define FOREACH(start, end) \
for (; (start) < (end); (start)++) \
{ \
// do something interesting \
}
Bad juju all the way around. Note that start
must correspond to an lvalue; you would not be able to call this as FOREACH(1,10)
, or FOREACH((a+b), c)
, or FOREACH(x++,y++)
. All of those would lead to a compile-time error (the operand of ++
must be an lvalue, and none of 1
, a+b
, or x++
qualify). Calling it as FOREACH(x, y++)
will do something you really don't want it to do. Similarly, you wouldn't want to call it as FOREACH(x, y())
.
You can guard against these problems to an extent by doing something like
#define FOREACH(start, end) \
do { \
int i; \
int j = end; \
for (i = start; i < j; i++) { \
// do something interesting \
} \
} while (0)
Essentially, you're creating local variables corresponding to your macro arguments. This protects against start
not being an lvalue, and against end
having a side effect that gets applied or being a function that gets called every iteration.
But if you're trying to encapsulate a loop that gets called frequently, put it in its own separate function. It's safer and easier to understand and maintain.

- 119,563
- 19
- 122
- 198
-
-
@Coder: Yes, lvalues are a thing in C - "An *lvalue* is an expression (with an object type other than `void`) that potentially designates an object;" - C 202x working draft, 6.3.2.1. – John Bode Feb 05 '23 at 03:19
Since C doesn't require statements to be on separate lines, you can simply smush together into one long line:
#define M while (...) { ...; ...; }
Or you could escape newlines in the macro definition:
#define M \
while (...) { \
...; \
...; \
}

- 2,175
- 1
- 16
- 19
#define something for(;;) printf("hooray, i'm in infinite loop!");
int main() { something }

- 15,882
- 9
- 57
- 104
-
3
-
3
-
4
-
I'm not sure if requires, but yes, it is at least a good practice to return something. – nothrow Apr 22 '11 at 21:05
This would be a more generic for loop
#include <stdio.h>
#include <string.h>
#define for_loop(start, end, incr) for(i = start; \
i < end; \
i += incr)
int main()
{
int i=0, j=5;
for_loop(i, j, 1)
printf("%d\n", i+1);
return 0;
}

- 149
- 1
- 2
- 7
-
Very concise while still human-readable, and it's extremely versatile (unlike the accepted answer which requires different declarations for different executions). Well done! – 255.tar.xz Jan 15 '20 at 01:18
#define foo(x) do { \
for(x=0;x<4;x++) x; \
} while(0) // note lack of trailing ;
or in gnu c:
#define foo(x) ({ \
for(x=0;x<4;x++) x; \
})
The latter can be used as a expression, although this one has type void, and thus is not very useful.

- 3,998
- 3
- 29
- 32
-
Don't you have a conflict between the macro parameter `x` and the control variable `x` in the for loop? And why the `do/while(0)`? – Lawrence Dol Apr 22 '11 at 20:55
-
@Software Monkey, the macro parameter `x` is the control variable, I wanted to keep it very simple. The `do`/`while(0)` is to ensure that it isn't accidentally used as eg `foo(i) += 12;` or something else that the compiler would likely happily allow. – David X Apr 22 '11 at 20:57
-
2Huh? So `foo(index)` tries to execute the statement `index` 4 times, using `index` as the control counter variable? – Lawrence Dol Apr 22 '11 at 20:59
-
-
2@Software Monkey: questioner didn't specify what the loop should actually do, presumably that can be filled in later. – Steve Jessop Apr 22 '11 at 21:09