简体   繁体   English

遍历 C 中的枚举?

[英]Iterate through enums in C?

let's say I have a couple of hardware registers which are defined within an enum:假设我有几个在枚举中定义的硬件寄存器:

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

I have default values for these registers(actually not decided in which way to define them, #define, array or enum...):我有这些寄存器的默认值(实际上并没有决定以哪种方式定义它们,#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    
}

I have a function which can read the hardware registers:我有一个可以读取硬件寄存器的函数:

uint8 readRegs(uint8 regaddr);

Now I would like to loop through registers , and on each element call the readRegs() function and compare it to the enum regvalues .现在我想遍历registers ,并在每个元素上调用readRegs()函数并将其与枚举regvalues进行比较。 It looks like:看起来像:

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

This will not work because it's not possible to iterate in enum in this way.这将不起作用,因为不可能以这种方式在枚举中迭代。 Does anybody have a better solution?有人有更好的解决方案吗? How to define the construct enum reg_values ?如何定义构造enum reg_values The enum registers must be fix (this can not be changes to array).枚举寄存器必须是固定的(这不能是对数组的更改)。

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. REG_MAX将是9MAX_NUM_REG_VALUES将是25所以你不能使用它们。 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:根据@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;

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:即以严重降低可读性为代价的“X 宏”:

// 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:同样,您可以使用 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM