在C中“分组”枚举值

时间:2013-06-21 07:32:58

标签: c enums

如果我有一些像

这样的枚举
typedef enum {
    AN_TRISTATE_0,
    AN_TRISTATE_1,
    AN_NOTHING,
    AN_MOTOR_1,
    AN_MOTOR_2,
    AN_MOTOR_3,
    AN_SENSOR_1,
    AN_SENSOR_2,
    AN_SENSOR_3,
    AN_SENSOR_4,
    AN_SENSOR_5
} adc_pin_func_t;

adc_pin_func_t a_particular_pin = ...

,是否有可能检查引脚是否属于特定组,例如引脚是AN_MOTOR的一部分或AN_SENSOR的一部分,而不是必须检查每个可能的每个项目基。

或者除了使用枚举之外,还有更有效的方法吗?

提前致谢

6 个答案:

答案 0 :(得分:22)

您可以为每个组创建掩码:

typedef enum {
    AN_TRISTATE_0     = 0x00001,
    AN_TRISTATE_1     = 0x00002,
    AN_TRISTATE_MASK  = 0x0000f,

    AN_NOTHING        = 0x00010,    // Should this be 0x00000 ?

    AN_MOTOR_1        = 0x00100,
    AN_MOTOR_2        = 0x00200,
    AN_MOTOR_3        = 0x00400,
    AN_MOTOR_MASK     = 0x00f00,

    AN_SENSOR_1       = 0x01000,
    AN_SENSOR_2       = 0x02000,
    AN_SENSOR_3       = 0x04000,
    AN_SENSOR_4       = 0x08000,
    AN_SENSOR_5       = 0x10000,
    AN_SENSOR_MASK    = 0xff000
} adc_pin_func_t;

然后使用&运算符简单地针对掩码测试组:

if (a_particular_pin & AN_SENSOR_MASK)
{
    // it's a sensor pin
}
else if (a_particular_pin & AN_MOTOR_MASK)
{
    // it's a motor pin
}
编辑:正如其他人建议使用范围一样,那么您可以为测试创建一个宏,这将允许您更改测试的执行方式而无需更改代码(总是一件好事):< / p>
#define IS_AN_SENSOR(x) (((x) & AN_SENSOR_MASK) != 0)
#define IS_AN_MOTOR(x) (((x) & AN_MOTOR_MASK) != 0)
// etc.

然后测试成为:

if (IS_AN_SENSOR(a_particular_pin))
{
    // it's a sensor pin
}
else if (IS_AN_MOTOR(a_particular_pin))
{
    // it's a motor pin
}
// etc

如果您需要更改为使用范围,则只需要更改宏(并且您显然需要定义范围最小值/最大值):

#define IS_AN_SENSOR(x) ((x) >= AN_SENSOR_START && (x) <= AN_SENSOR_END)
// etc

答案 1 :(得分:4)

你可以自由选择你的枚举值,所以你可以做这样的事情

typedef enum {
    AN_TRISTATE_0 = 0x0001,
    AN_TRISTATE_1 = 0x0002,
    AN_NOTHING = 0x0000,
    AN_MOTOR_1 = 0x0010,
    AN_MOTOR_2 = 0x0020,
    AN_MOTOR_3 = 0x0030,
    AN_SENSOR_1 = 0x0100,
    AN_SENSOR_2 = 0x0200,
    AN_SENSOR_3, /*and so on*/
    AN_SENSOR_4,
    AN_SENSOR_5
} adc_pin_func_t;

然后您可以比较位以检查类别。例如,电机类型是唯一具有非零(AN_MOTOR_2 & 0x00F0)

的类别

答案 2 :(得分:3)

你可以做一个

typedef enum {
    AN_TRISTATE_START,
    AN_TRISTATE_0 = AN_TRISTATE_START,
    AN_TRISTATE_1,
    AN_TRISTATE_END = AN_TRISTATE_1,

    AN_NOTHING,

    AN_MOTOR_START,
    AN_MOTOR_1 = AN_MOTOR_START,
    AN_MOTOR_2,
    AN_MOTOR_3,
    AN_MOTOR_END = AN_MOTOR_3,

    AN_SENSOR_START,
    AN_SENSOR_1 = AN_SENSOR_START,
    AN_SENSOR_2,
    AN_SENSOR_3,
    AN_SENSOR_4,
    AN_SENSOR_5,
    AN_SENSOR_END = AN_SENSOR_5
} adc_pin_func_t;

bool inline
is_sensor(int pin)
{
    return AN_SENSOR_START <= pin
                           && pin <= AN_SENSOR_END
}

然后在你的代码中

if ( is_sensor(pin) )
{
    /* body */
}

这样您就不必关心屏蔽特定值了。如果组包含大量值,则可能很有用。

答案 3 :(得分:1)

您可以在2的指数中为枚举值赋值。然后您可以简单地使用按位AND和OR掩码。所以你可以分配像1,2,4,8,16,32 ......这样的值。


typedef enum {
    AN_TRISTATE_0 = 1,
    AN_TRISTATE_1 = 2,
    AN_NOTHING = 4,
    AN_MOTOR_1 = 8,
    AN_MOTOR_2 = 16,
    AN_MOTOR_3 = 32,
    AN_SENSOR_1 = 64,
    AN_SENSOR_2 = 128,
    AN_SENSOR_3 = 256,
    AN_SENSOR_4 = 512,
    AN_SENSOR_5 = 1024
} adc_pin_func_t;

然后用电机类型检查,你可以用(32 + 16 + 8)= 56进行AND。所以pin & 56,如果非零则意味着它是电机类型。

答案 4 :(得分:0)

如果你真的想在你的枚举中有一些模块性(“硬编码”枚举值也是一个有效的方法),你可以实现一个具有一些OOP风格的结构。设计变得更加复杂,但使用仍然很简单:

#include <stdio.h>
#include <string.h>

// Every enum will have its first value start at the value of the previous enum's last member PLUS ONE 
#define OFFSET_ENUM_MOTOR  (                        sizeof(adc_pin_tristate_t) )
#define OFFSET_ENUM_SENSOR ( OFFSET_ENUM_MOTOR   +  sizeof(adc_pin_motor_t)    )


///////////////////////////////////////////////////////////////////////////////
// Enum
typedef enum {
    AN_TRISTATE_0,
    AN_TRISTATE_1,
    AN_NOTHING
} adc_pin_tristate_t;

typedef enum {
    AN_MOTOR_1 = OFFSET_ENUM_MOTOR,
    AN_MOTOR_2,
    AN_MOTOR_3
} adc_pin_motor_t;

typedef enum {
    AN_SENSOR_1 = OFFSET_ENUM_SENSOR,
    AN_SENSOR_2,
    AN_SENSOR_3,
    AN_SENSOR_4,
    AN_SENSOR_5
} adc_pin_sensor_t;
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// Struct for abstraction
typedef struct adc_pin_func2_t{

    // our "enum value"
    unsigned int enum_id;

    // return is the enum is a motor one 
    int(*isMotor)(struct adc_pin_func2_t*);

} adc_pin_func2_t;
// Struct
///////////////////////////////////////////////////////////////////////////////


// Member methods : return if the enum is a motor one
int
PinFunc_isMotor(
    adc_pin_func2_t *This /* object */
    )
{
    return ( (This->enum_id>=OFFSET_ENUM_MOTOR) && (This->enum_id<OFFSET_ENUM_SENSOR) );
}

// Creation of the structure

// Initialization
static void 
PinFunc_Init(
        adc_pin_func2_t *This, /* output */
        unsigned int identifier /* old enum identifier */ 
            )
{
    // copy members
    This->enum_id = identifier;

    //copy methods (do not forget to do it !)
    This->isMotor = PinFunc_isMotor;


}

// Constructor
adc_pin_func2_t 
PinFunc_Create(
        unsigned int identifier /* old enum identifier */ 
              )
{
   adc_pin_func2_t This;
   PinFunc_Init(&This, identifier);

   return This;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
main()
{
   adc_pin_func2_t pin = PinFunc_Create(AN_NOTHING);
   printf("%d \n", pin );
   printf("%d \n", pin.isMotor(&pin) );

   adc_pin_func2_t pin2 = PinFunc_Create(AN_MOTOR_2);
   printf("%d \n", pin2 );
   printf("%d \n", pin2.isMotor(&pin2) );
}

pin.isMotor(&pin)之类的成员函数的使用不是很优雅(我们重复pin),但它是C的缺点,它不是OOP语言。

答案 5 :(得分:0)

如果您不想手动维护非重叠值,那么您几乎可以自动为您处理所有这些值。您唯一需要弄清楚的是组中的最大位数:

#define PIN_GROUP_SHIFT 4
#define GET_PIN_GROUP(x) (adc_pin_group_t)((y) >> PIN_GROUP_SHIFT)

#define PIN_GROUP_START(x) XX_GROUP_##x = ((GROUP_##x << PIN_GROUP_SHIFT) - 1),

enum {
    GROUP_TRISTATE,
    GROUP_NOTHING,
    GROUP_MOTOR,
    GROUP_SENSOR
} adc_pin_group_t;

typedef enum {
    PIN_GROUP_START(TRISTATE)
    AN_TRISTATE_0,
    AN_TRISTATE_1,

    PIN_GROUP_START(NOTHING)
    AN_NOTHING,

    PIN_GROUP_START(MOTOR)
    AN_MOTOR_1,
    AN_MOTOR_2,
    AN_MOTOR_3,

    PIN_GROUP_START(SENSOR)
    AN_SENSOR_1,
    AN_SENSOR_2,
    AN_SENSOR_3,
    AN_SENSOR_4,
    AN_SENSOR_5
} adc_pin_func_t;

要确定枚举中条目的类型,请使用GET_PIN_GROUP(x),并将其与adc_pin_group_t枚举中的任何值进行比较。如果有帮助,你甚至可以switch得到结果。

然而,AN_NOTHING条目让我想知道你的枚举是否意味着与每个条目的特定值对齐。是与引脚相关的特定值,您可能无法任意分配。在这种情况下,您可能需要尝试复杂的事情(我还没有测试过):

#define GET_PIN_VALUE(x) ((x) & ((1 << PIN_GROUP_SHIFT) - 1)
#define PIN_GROUP_START(x) \
    WW_GROUP_##x, \
    XX_GROUP_##x = (GROUP_##x << PIN_GROUP_SHIFT) \
                 + GET_PIN_INDEX(WW_GROUP_##x) - 1,

如果您需要了解原始枚举使用的值,请使用GET_PIN_INDEX(x)