Difference between revisions of "Range-based for loop"

From vegard.wiki
Jump to navigation Jump to search
(new page)
 
(→‎Usage: add output)
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
One of my pet peeves is the regular counting <tt>for</tt> loop in C where you have to repeat the variable name 3 times. This is error-prone in the case of nested loops, since the compiler has no way to know that you meant to increment <tt>j</tt> and not <tt>i</tt>. To prevent this kind of error, you can use a few helper macros that iterate over a range (forwards or backwards).
 
One of my pet peeves is the regular counting <tt>for</tt> loop in C where you have to repeat the variable name 3 times. This is error-prone in the case of nested loops, since the compiler has no way to know that you meant to increment <tt>j</tt> and not <tt>i</tt>. To prevent this kind of error, you can use a few helper macros that iterate over a range (forwards or backwards).
  
Definitions:
+
=== Definitions ===
  
 
<source lang="C">
 
<source lang="C">
 +
// low .. (high - 1)
 
#define RANGE(var, low, high) \
 
#define RANGE(var, low, high) \
        (typeof(0 ? (low) : (high)) var = (low), _end = (high); var < _end; ++var)
+
    (typeof(0 ? (low) : (high)) var = (low), _end = (high); var < _end; ++var)
  
 
// https://stackoverflow.com/a/5458283
 
// https://stackoverflow.com/a/5458283
 +
// (high - 1) .. low
 
#define REVERSE_RANGE(var, high, low) \
 
#define REVERSE_RANGE(var, high, low) \
        (typeof(0 ? (low) : (high)) var = (high), _end = (low); var-- > _end; )
+
    (typeof(0 ? (low) : (high)) var = (high), _end = (low); var-- > _end; )
 
</source>
 
</source>
  
Note that <tt>typeof</tt> is a GNU/gcc extension, so this will not work on e.g. MSVC.
+
This automatically deduces the type of the index variable, so that e.g. <tt>RANGE(i, -1, 1)</tt> will use <tt>int</tt>, while <tt>RANGE(i, 0UL, 1UL)</tt> will use <tt>unsigned long</tt>. Note that <tt>typeof</tt> is a GNU/gcc extension, so this will not work on e.g. MSVC.
  
Usage:
+
=== Usage ===
  
 +
{| class="wikitable"
 +
|-
 +
! Code
 +
! Output
 +
|- style="vertical-align:top;"
 +
|
 
<source lang="C">
 
<source lang="C">
 
for RANGE(i, -1, 5) {
 
for RANGE(i, -1, 5) {
        printf("%d\n", i);
+
    printf("%d\n", i);
 
}
 
}
 
</source>
 
</source>
 +
||
 +
<pre>
 +
-1
 +
0
 +
1
 +
2
 +
3
 +
4
 +
</pre>
 +
|- style="vertical-align:top;"
 +
|
 +
<source lang="C">
 +
for REVERSE_RANGE(i, 5, -1) {
 +
    printf("%d\n", i);
 +
}
 +
</source>
 +
||
 +
<pre>
 +
4
 +
3
 +
2
 +
1
 +
0
 +
-1
 +
</pre>
 +
|}
  
 
[[Category:C]]
 
[[Category:C]]
 
[[Category:Programming]]
 
[[Category:Programming]]
 +
[[Category:C preprocessor snippets]]

Latest revision as of 08:43, 28 April 2020

One of my pet peeves is the regular counting for loop in C where you have to repeat the variable name 3 times. This is error-prone in the case of nested loops, since the compiler has no way to know that you meant to increment j and not i. To prevent this kind of error, you can use a few helper macros that iterate over a range (forwards or backwards).

Definitions

// low .. (high - 1)
#define RANGE(var, low, high) \
    (typeof(0 ? (low) : (high)) var = (low), _end = (high); var < _end; ++var)

// https://stackoverflow.com/a/5458283
// (high - 1) .. low
#define REVERSE_RANGE(var, high, low) \
    (typeof(0 ? (low) : (high)) var = (high), _end = (low); var-- > _end; )

This automatically deduces the type of the index variable, so that e.g. RANGE(i, -1, 1) will use int, while RANGE(i, 0UL, 1UL) will use unsigned long. Note that typeof is a GNU/gcc extension, so this will not work on e.g. MSVC.

Usage

Code Output
for RANGE(i, -1, 5) {
    printf("%d\n", i);
}
-1
0
1
2
3
4
for REVERSE_RANGE(i, 5, -1) {
    printf("%d\n", i);
}
4
3
2
1
0
-1