looping through enum values
Solution 1
Given
enum Foo {Bar=0,Baz,...,Last};
you can iterate the elements like:
for(int i=Bar; i<=Last; i++) {
...
}
Note that this exposes the really-just-an-int nature of a C enum. In particular, you can see that a C enum doesn't really provide type safety, as you can use an int in place of an enum value and vice versa. In addition, this depends on the declaration order of the enum values: fragile to say the least. In addition, please see Chuck's comment; if the enum items are non-contiguous (e.g. because you specified explicit, non-sequential values for some items), this won't work at all. Yikes.
Solution 2
It's a bit of a kludge (as is the entire concept so... eh...) but if you're going to do this multiple times, and you want to be able to deal with the possibility of non-contiguous enums, you can create a (global constant) array, and have (to use ennukiller's example) Directions directions[4] = {East, West, North, South}; and then in your loop you can talk about directions[i] rather than iterating directly over the directions themselves...
As I said, it's ugly, but it's slightly less fragile I think...
Solution 3
If you enum is defined as follows:
enum Direction { East, West, North, South};
You can loop through it this way:
for ( int direction = East; direction <= South; ++direction)
{
/* Do something with Direction
}
Solution 4
For non-contiguous enums you can iterate over valid values by doing:
enum {
value_one = 0,
value_two = 1,
value_three = 3,
value_max
}
for ( i = value_one; i < value_max; i++ )
{
switch(i)
{
case value_one:
case value_two:
case value_three:
case value_four:
{
/* ... Do something with valid enum value ... */
}
break;
default:
/* Found an invalid enum entry; ignore it */
break;
}
}
Solution 5
In search of this, I just concocted the following solution which fulfilled my own requirements. I thought I'd post it here for people searching something similar.
Say I have an enum.
typedef NS_ENUM (NSInteger, ISDirection) {
ISDirectionUp,
ISDirectionDown,
ISDirectionLeft,
ISDirectionRight
};
To be able to loop over it, I define the following preprocessor macro.
#define ISDirectionAllAsDir ISDirection dir = ISDirectionUp; dir <= ISDirectionRight; dir++
Then I use it inside a loop, as such:
for(ISDirectionAllAsDir) {
NSLog(@"Direction %d", dir);
}
This puts the logic for iterating in one place (the macro) which increases code maintainability.
Comments
-
Frank almost 2 years
Is it possible to loop through enum values in Objective-C?
-
Brian Postow over 14 yearsRetagged: this is (AFAIK) a pure C question. You'll get more response with the more general tagging.
-
pbh101 over 14 yearsIt also answers the question for people searching for it in Obj-C. Added that tag back.
-
-
Jorge Israel Peña over 14 yearsI've never done this, so I have some questions. Shouldn't it be Direction.East and Direction.South? Also shouldn't the condition be direction <= Direction.South? Again I've never done this, I'm not trying to correct you, just would like to learn.
-
Ed S. over 14 yearsIs there a better way to do this? Just curious, but it seems like depending on the declaration order of the enum values is fragile at best.
-
pxl over 14 years@blaenk: i think you're confusing structs with enums.
-
Chuck over 14 yearsIt also requires that all the items in the enum be contiguous. But it's the best you'll get.
-
Chuck over 14 years@Ed: Yes this is fragile, and no there's not a better way. It's not advisable to do this at all.
-
Frank over 14 yearsit doesn't recognize Foo in the for looo for me.
-
Elise van Looij over 14 yearsOne could be more explicit as in enum Direction { East =1, West=2, North=3, South=4}; or even enum Direction { East =313, West, North, South}; but it all comes down to the same thing, except that numbering each element leaves more room for programmer error. In the end it seems to me to be as fragile or non-fragile as any const declaration.
-
new123456 over 12 yearsIt's a pure nitpick, but it's spelled
vice versa
. -
ArtOfWarfare over 11 yearsLooks good to me. Is there a way that we can add some kind of macro that will automatically generate C-arrays for us for each enum type we declare?
-
Miles Rout over 10 years@ArtOfWarfare I use this all the time:
#define ENUM(type, ...) enum _##type { __VA_ARGS__ }; enum _##type type##s[] = { __VA_ARGS__ }
, though that will only work for contiguous ones. I don't use non-contiguous enums, because that to me signals bad design. Also I havetypedef struct _list List;
,typedef enum _direction Direction
everywhere in my C code that uses this macro, which is why I'm prefixing the _ to the type.ENUM(direction, NORTH, EAST, SOUTH, WEST);
givesenum _direction { NORTH, EAST, SOUTH, WEST }; enum _direction directions = { NORTH, EAST, SOUTH, WEST };
I like it. -
new123456 over 10 years@MilesRout There's actually a minimum character change of 6 characters. Since it's a 2 character fix, I can't fix it.
-
Charles over 9 yearsNote that if the values are not contiguous, but is a bitmask enum, you can use:
for (int i=1; i<=Last; i=i*2)
-
Powerslave over 8 yearsPlease pay attention to the fact that, by specification, representation of enums in C is not defined, i.e. although most compilers treat them as
int
values, you cannot trust such an assumption. With this in mind, there is, unfortunately, no source-code-portable solution for this problem (known to me). -
Offler almost 7 years@JorgeIsraelPeña In languages which are using enums as objects like Java or C# -> yes. C you can think of East like global. You are not allowed to define "East" in any other enum.
-
Jorge Bellon over 6 yearsIn this case, I wouldn't use a loop at all. Just leave the the switch-case blocks one after another, it will be cleaner and sometimes more efficient.
-
Matt Conway over 6 yearsSure, I completely agree with you and I wouldn't write this in production code; the only reason I encased the switch within a loop is because that's what was being asked by the original poster ;)
-
Kami Kaze over 4 years@Powerslave AFAIR It has to be representable as an integer or larger.
-
Powerslave over 3 years@GoodbyeSE I haven't been concerned with the topic for quite a while, so don't take my word for it, but I can't recall such requirement. I, however, recall being warned that treating them as comparable integer values has serious pitfalls as the standard does not define such behavior.