通过C中的枚举迭代?

时间:2017-03-23 10:02:50

标签: c enums

假设我有一些枚举中定义的硬件寄存器:

typedef enum registers
{
REG1 = 0,
REG2 = 1,
REG3 = 2,
REG4 = 4,
REG5 = 6,
REG6 = 8,

REG_MAX,

}

我有这些寄存器的默认值(实际上没有决定以哪种方式定义它们,#define,array或enum ...):

// This is just conceptual, not really an enum, array or #define :)
typedef enum values
{
VALUE_REG1 = A,
VALUE_REG2 = B,
VALUE_REG3 = C,
VALUE_REG4 = 53,
VALUE_REG5 = 88,
VALUE_REG6 = 24,

MAX_NUM_REG_VALUES    
}

我有一个可以读取硬件寄存器的函数:

uint8 readRegs(uint8 regaddr);

现在我想遍历寄存器枚举,并在每个元素上调用 readRegs()函数并将其与枚举reg_values进行比较。它看起来像:

   registers regs;
   reg_values values;
   uint8 readfromregs;

   for (regs = REG1; regs <= REG_MAX; regs++)
   {
      readfromregs = readRegs(regs);
         for (values = VALUE_REG1; reg_values <= MAX_NUM_REG_VALUES; reg_values++)
         {
           if (readfromregs != values)
           {
                 // Value not correct
           }

           else
           {
                 // value correct
           }
        }
   }

这不起作用,因为不可能以这种方式迭代枚举。有人有更好的解决方案吗?如何定义构造 enum reg_values ?    必须修复枚举寄存器(这不能更改为数组)。

2 个答案:

答案 0 :(得分:4)

我可能会定义一个结构

struct RegInfo
{
    registers number;
    values defaultValue;
}

然后我会创建一个与寄存器编号匹配的数组到默认值

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

现在迭代寄存器:

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

如果你想要一个内部循环敌人的每个值,除了数组之外的相同技巧可以直接使用值

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

您可能会忘记在相关阵列中放置新值/寄存器,但这是单元测试的用途。

答案 1 :(得分:1)

REG_MAX为9,MAX_NUM_REG_VALUES为25,因此您无法使用。您必须以不同的方式枚举常量。

基于@JeremyP的另一个答案中的struct解决方案,您可以使用第三个枚举作为实际索引:

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;

这使得某些方法可以提高数据完整性:

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");

这是我建议的解决方案。

如果你对数据完整性非常迂腐,并且想避免代码重复,那么你也可以使用一些邪恶的宏魔法。即&#34; X宏&#34;这是以严重降低可读性为代价的:

// 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
}

同样,您可以使用X宏创建枚举:

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;