检查变量是否在C中具有枚举值的更好方法

时间:2018-07-19 18:07:29

标签: c performance enums code-readability

我的问题与代码的外观及其性能有关。

假设我有一个枚举:

typedef enum {
   THIS_IS_A_VALUE1 = 65,
   THIS_IS_A_VALUE2 = 10,
   THIS_IS_A_VALUE3 = 45,
   THIS_IS_A_VALUE4 = 5,
   THIS_IS_A_VALUE5 = 7
} I_AM_AN_ENUM;

,我想检查某个变量是否包含枚举中的值之一: 我考虑了三种方法:

1。

int val;
if(val != THIS_IS_A_VALUE1 && val != THIS_IS_A_VALUE2 && val != THIS_IS_A_VALUE3...)
{
// val is different than all values
// do something
}

2。

if(val != THIS_IS_A_VALUE1)
{
// keep blank
}
else if(val != THIS_IS_A_VALUE2)
{
// keep blank
}
else if(val != THIS_IS_A_VALUE3)
{
// keep blank
}....
else
{
// val is different than all values
// do something
}

3。

switch(val)
{
case THIS_IS_A_VALUE1:
case THIS_IS_A_VALUE2:
case THIS_IS_A_VALUE3:
..
..
default:
// val is different than all values
// do something
}

说实话,我发现2和3很难看,尤其是当枚举中包含很多值时。 第一种方法也可能很丑陋,但比其他方法更好,尽管根据我的理解,使用很多&&可能会降低性能。

所以总结一下:可读性和性能对我来说非常重要, 我真的不确定哪个选项是最好的, 也许还有其他方法可以做到?

谢谢。

编辑:我忘了说值不是 连续的,是的,我不能真正更改它。

3 个答案:

答案 0 :(得分:1)

我认为没有第四种方法会更好。我认为选项3是最好的选择,因为这样编译器可以检查您是否已处理所有情况。

当您决定向枚举添加选项时,这非常有用。然后,编译器会警告您,这样您就不会忘记包括新的情况。

答案 1 :(得分:1)

枚举与使用宏定义常量本质上是一样的,除了枚举将一组关联的常量包装为数据类型。这样可以使您的代码更具自记录性,但实际上并没有提供任何其他功能。


以下是您的问题引起的两种情况。

情况1 :枚举中的值不是连续的,表示

enum Foo { FIRST=0, MIDDLE=40, LAST=12 };

bool isInFoo(enum Foo x){
bool found = false;
switch(x){
   case FIRST: found = true;  break;
   case MIDDLE: found = true; break;
   case LAST: found = true; break;
   }
return found;
}

这样,如果您不处理switch中的所有枚举,则会收到编译时警告。

情况2 :值是连续的。然后检查enum Bar x是否在枚举中,您可以执行以下操作

enum Bar { FIRST=10, MIDDLE=11, LAST=12 };
bool isInBar(enum Bar x){ return x >= FIRST && x <= LAST; }

编辑:根据下面的评论,您可以将Bar的“虚拟末尾”条目添加为OUT_OF_RANGE = LAST+1,然后在功能isInBar()中进行检查x小于OUT_OF_RANGE,这样,如果我们向枚举添加更多元素,则不必更改isInBar()函数,因为新添加的值应小于OUT_OF_RANGE。最后,取决于您是否包括在内。


请注意,在情况2中,枚举值不一定需要是连续的序列号,您可以将它们保留为所需的任何序列,但是随后需要相应地更改isInBar()

enum FooBar { FIRST=3, SECOND=6, THIRD=9, FOURTH=15, LAST=12 };

bool isInFooBar(enum FooBar x){
bool found = false;
   for(int t=3;t<=15;t+=3)
      if(x == t) {
         found = true;
         break;
      }
return found;
}

答案 2 :(得分:0)

您可能希望封装检查逻辑并使用特殊名称来执行范围检查。采用这种方法可以提供一些非常好的集合逻辑操作,例如检查是否在这组值中或检查它是否与另一组相交,等等。

尽管我在C ++文件中使用Visual Studio 2005进行了编译,但我还没有测试过其中任何一个,但似乎可以使用它进行编译。换句话说,您可能需要对此进行一些调整。

typedef enum {
   THIS_IS_A_VALUE1 = 65,
   THIS_IS_A_VALUE2 = 10,
   THIS_IS_A_VALUE3 = 45,
   THIS_IS_A_VALUE4 = 5,
   THIS_IS_A_VALUE5 = 7
} I_AM_AN_ENUM;

typedef enum {
    IS_A_THIS_IS_A_VALUE1 = 0x01,
    IS_A_THIS_IS_A_VALUE2 = 0x02,
    IS_A_THIS_IS_A_VALUE3 = 0x04,
    IS_A_THIS_IS_A_VALUE4 = 0x08,
    IS_A_THIS_IS_A_VALUE5 = 0x10,
    IS_A_THIS_IS_VALUE123 = 0x07,       // bitwise Or of first three masks.
    IS_A_THIS_IS_VALUE_ANY = 0x1f       // is any of the values.
} IS_A_I_AM_ENUM;

struct {
    I_AM_AN_ENUM eVal;
    ULONG        ulMask;
} testArray[] = {
   {THIS_IS_A_VALUE1, IS_A_THIS_IS_A_VALUE1},
   {THIS_IS_A_VALUE2, IS_A_THIS_IS_A_VALUE2},
   {THIS_IS_A_VALUE3, IS_A_THIS_IS_A_VALUE3},
   {THIS_IS_A_VALUE4, IS_A_THIS_IS_A_VALUE4},
   {THIS_IS_A_VALUE5, IS_A_THIS_IS_A_VALUE5}
};

bool isInBar (I_AM_AN_ENUM x, ULONG ulCheckMask)
{
    int i;
    for (i = 0; i < sizeof(testArray)/sizeof(testArray[0]); i++) {
        if (testArray[i].eVal == x) {
           if (testArray[i].ulMask & ulCheckMask) return true;
           else break;
        }
    }
    return false;
}

// check a value against a range.
I_AM_AN_ENUM eVal = THIS_IS_A_VALUE3;

// check if eVal is Value3 or a Value 4
if (isInBar (eVal, IS_A_THIS_IS_A_VALUE3 | IS_A_THIS_IS_A_VALUE4)) // do something
if (isInBar (eVal, IS_A_THIS_IS_VALUE123 & ~IS_A_THIS_IS_A_VALUE1)) // do something
if (isInBar (eVal, IS_A_THIS_IS_VALUE_ANY))  // do something.