2

I have legacy code that is using an enum as a range and iterating through the range. I need to port this to a new platform and make it safer.

Note: enums are not safe to iterate through as there may be "holes" or gaps between values.

I'm looking for a safe C language pattern for a range type.

For example, given a range (RED, VIOLET, BLUE, GREEN, YELLOW, ORANGE), I want to iterate through each value, like "FOR color IN (RED, VIOLET, BLUE, GREEN, YELLOW, ORANGE)".

When I search SO and the web, I get replies about the range of a data type, such as the range of an integer.

This code will reside on an embedded system that uses an ARM7 processor.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • Can there be gaps by default? You could always specify the values of the enums, like `enum { zero = 0, one = 1, two = 2};`, no? – Dan Fego Jan 05 '12 at 17:52
  • The problem is when somebody inserts "four = 4" into the `enum`, then undefined behavor will result (or hard to find bugs). – Thomas Matthews Jan 05 '12 at 18:14

2 Answers2

3

An enum can do just fine, as long as you let the compiler choose values. This way, there would be no holes. You could, for example, do this:

enum colors {
    FIRST_COLOR=0,
    RED=FIRST_COLOR, VIOLET, BLUE, GREEN, YELLOW, ORANGE,
    NUM_COLORS
}

enum colors color;
for (color=FIRST_COLOR; color<NUM_COLORS; color++) {
    // whatever
}

And a quote from the ANSI C standard:

If the first enumerator has no = , the value of its enumeration constant is 0. Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant

ugoren
  • 16,023
  • 3
  • 35
  • 65
  • My compiler, IAR, is giving me *"enumerated type mixed with another type"* for `for (color = 0; color < ORANGE; color++)`, but i guess that is because of the 0. – Thomas Matthews Jan 05 '12 at 18:19
  • I'm used for gcc, where enums and integers can freely be mixed. I actually wish it did warn about such mixes. I think using FIRST_COLOR should satisfy any compiler. – ugoren Jan 05 '12 at 19:48
  • I really like the `FIRST_COLOR` trick. This makes the iteration loops more readable and less prone to "accidents" when the enum list is modified. – Thomas Matthews Jan 06 '12 at 16:09
1

You could use an array:

 static Color colors[] = {Red, Violet, Green, Yellow, Orange};
 #define SIZE(x) sizeof(x)/sizeof(*x)

 for(x=0; x<SIZE(colors); x++){
      //do stuff with colors[x]
 }

Otherwise, the usual pattern you see is:

 enum Colors {FirstColor, Red=0, Violet, Green, Yellow, Orange, LastColor};

 for(x=FirstColor; x<LastColor; x++){
     //do stuff with x.
 }

But if the way to iterate them changes, you could always define a function nextcolor(), and:

 for(x=FirstColor;x<LastColor;x=nextcolor(x)){
     //do stuff with x.
 }
Dave
  • 10,964
  • 3
  • 32
  • 54