Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Grouping" enum values in C

Tags:

c

enums

If I had some enums like

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;

and

adc_pin_func_t a_particular_pin = ...

, would it be possible it check if the pin is part of a particular group, e.g pin is part of AN_MOTOR or part of AN_SENSOR, instead of having to check against each item in each possible group.

Or are there more efficient ways of doing this, other than using enums?

Thanks in advance

like image 318
A Person Avatar asked Jun 21 '13 07:06

A Person


People also ask

Can enums have multiple values?

The Enum constructor can accept multiple values.

Can we assign value to enum in C?

We can also provide the values to the enum name in any order, and the unassigned names will get the default value as the previous one plus one. The values assigned to the enum names must be integral constant, i.e., it should not be of other types such string, float, etc.

Why is enum 4 bytes?

The size is four bytes because the enum is stored as an int . With only 12 values, you really only need 4 bits, but 32 bit machines process 32 bit quantities more efficiently than smaller quantities. Without enums, you might be tempted to use raw integers to represent the months.


4 Answers

You could create masks for each of the groups:

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;

And then simply test a group against the mask using the & operator:

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
}

EDIT: As others have suggested using a range, then you could probably create a macro for the test, which would allow you to change how the test is performed without the need to change the code (always a good thing):

#define IS_AN_SENSOR(x) (((x) & AN_SENSOR_MASK) != 0)
#define IS_AN_MOTOR(x) (((x) & AN_MOTOR_MASK) != 0)
// etc.

and then the test becomes:

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

If you then needed to change to using a range then only the macros need to change (and you'd obviously need to define the range min/max):

#define IS_AN_SENSOR(x) ((x) >= AN_SENSOR_START && (x) <= AN_SENSOR_END)
// etc
like image 140
trojanfoe Avatar answered Sep 25 '22 21:09

trojanfoe


You are free to choose your enum values, so you could do something like this

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;

Then you can compare bits to check categories. For example, a motor type is the only category that will have non-zero (AN_MOTOR_2 & 0x00F0)

like image 36
Bathsheba Avatar answered Sep 25 '22 21:09

Bathsheba


You can do a

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
}

and then in your code

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

This way you don't have to care about masking particular values. May be useful if groups contain a lot of values.

like image 29
Michael Pankov Avatar answered Sep 24 '22 21:09

Michael Pankov


You can give values to the enum in exponents of 2. Then you can simply use bitwise AND and OR masks. So you can assign values like 1,2,4,8,16,32... so on.


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;

Then for checking with motor type, you can AND with (32+16+8) = 56. So pin & 56, if non zero will mean it is of motor type.

like image 41
Atmaram Shetye Avatar answered Sep 25 '22 21:09

Atmaram Shetye