Iterate through enums in C?

I'd probably define a struct

struct RegInfo
{
    registers number;
    values defaultValue;
}

Then I would create an array matching the register number to the default value

struct RegInfo registerInfo[] =
{
    { REG1, VALUE_REG1 },
    { REG2, VALUE_REG2 },
    { REG3, VALUE_REG3 },
    { REG4, VALUE_REG4 },
    { REG5, VALUE_REG5 },
    { REG6, VALUE_REG6 },
};

Now to iterate the registers:

for (int i = 0 ; i < sizeof registerInfo / sizeof(RegInfo) ; ++i)
{
    values value = readFromReg( registerInfo[i].number);
    if (value != registerInfo[i].defaultValue)
    {
         // Not the default
    }
}

If you want an inner loop foe each value, same trick except the array can be directly of the values

values allValues[] = { VALUE_REG1, Value_REG2, ... , VALUE_REG6 };

There is a risk that you'll forget to put new values/registers in the relevant array, but that's what unit testing is for.


REG_MAX will be 9 and MAX_NUM_REG_VALUES will be 25 so you can't use those. You'll have to enumerate the constants in a different way.

Based on the struct solution in another answer by @JeremyP, you could use a 3rd enum for the actual indices:

typedef enum
{
  REG_INDEX1 = REG1,
  REG_INDEX2 = REG2,
  REG_INDEX3 = REG3,
  REG_INDEX4 = REG4,
  REG_INDEX5 = REG5,
  REG_INDEX6 = REG6,
  REG_INDEX_N // number of registers
} reg_index;

This enables some ways to improve data integrity:

struct RegInfo registerInfo[] =
{
  [REG_INDEX1] = { REG1, VALUE_REG1 },
  [REG_INDEX2] = { REG2, VALUE_REG2 },
  [REG_INDEX3] = { REG3, VALUE_REG3 },
  [REG_INDEX4] = { REG4, VALUE_REG4 },
  [REG_INDEX5] = { REG5, VALUE_REG5 },
  [REG_INDEX6] = { REG6, VALUE_REG6 },
};

_Static_assert(sizeof(registerInfo)/sizeof(*registerInfo) == REG_INDEX_N, 
               "Enum not in sync with array initializer");

This is the solution I would recommend.


If you are very pedantic with data integrity and want to avoid code repetition, there is also some evil macro magic you can use. Namely "X macros" that come at the expense of severely reduced readability:

// whatever A, B and C is supposed to be
#define A 10
#define B 11
#define C 12

#define REG_LIST \
  X(0, A)        \
  X(1, B)        \
  X(2, C)        \
  X(4, 53)       \
  X(6, 88)       \
  X(8, 24)       \

int main (void)
{
  // iterate through the value pairs:
  #define X(reg, val) printf("reg: %d val:%.2d\n", reg, val);
  REG_LIST
  #undef X
}

Similarly, you can use X macros to create the enums:

typedef enum // create REG1, REG2, REG4 etc
{
  #define X(key, val) REG##key = key,
  REG_LIST
  #undef X
} registers;

typedef enum // create VALUE_REG1, VALUE_REG2, VALUE_REG4 etc
{
  #define X(key, val) VALUE_REG##key = val, 
  REG_LIST
  #undef X
} values;

Tags:

C

Enums