looping through enum values

71,476

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.

Share:
71,476
Frank
Author by

Frank

Cross platform Mobile developer

Updated on July 09, 2022

Comments

  • Frank
    Frank almost 2 years

    Is it possible to loop through enum values in Objective-C?

    • Brian Postow
      Brian Postow over 14 years
      Retagged: this is (AFAIK) a pure C question. You'll get more response with the more general tagging.
    • pbh101
      pbh101 over 14 years
      It also answers the question for people searching for it in Obj-C. Added that tag back.
  • Jorge Israel Peña
    Jorge Israel Peña over 14 years
    I'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.
    Ed S. over 14 years
    Is 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
    pxl over 14 years
    @blaenk: i think you're confusing structs with enums.
  • Chuck
    Chuck over 14 years
    It also requires that all the items in the enum be contiguous. But it's the best you'll get.
  • Chuck
    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
    Frank over 14 years
    it doesn't recognize Foo in the for looo for me.
  • Elise van Looij
    Elise van Looij over 14 years
    One 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
    new123456 over 12 years
    It's a pure nitpick, but it's spelled vice versa.
  • ArtOfWarfare
    ArtOfWarfare over 11 years
    Looks 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
    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 have typedef 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); gives enum _direction { NORTH, EAST, SOUTH, WEST }; enum _direction directions = { NORTH, EAST, SOUTH, WEST }; I like it.
  • new123456
    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
    Charles over 9 years
    Note 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
    Powerslave over 8 years
    Please 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
    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
    Jorge Bellon over 6 years
    In 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
    Matt Conway over 6 years
    Sure, 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
    Kami Kaze over 4 years
    @Powerslave AFAIR It has to be representable as an integer or larger.
  • Powerslave
    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.