Elad Weiss
Elad Weiss

Reputation: 4002

Forcing enum field to 8 bits in standard C with bitfields

I saw few questions here about how to force an enum to 8 or 16 bits. The common answer was that it can be done in C++11 or higher. Unfortunately, I don't have that luxury.

So, here is what I'm thinking. I only need the enum to be 8 bits when it's in a struct whose size I want to minimize. So:

Option A:

typedef enum { A, B, C, MAX = 0xFF } my_enum;

struct my_compact_struct
{
    my_enum field1 : 8; // Forcing field to be 8 bits 
    uint8_t something;
    uint16_t something_else;
};

I think most or all optimizers should be smart enough to handle the 8 bitfield efficiently.

Option B:

Not use an enum. Use typedef and constants instead.

typedef uint8_t my_type;

static const my_type A = 0;
static const my_type B = 1;
static const my_type C = 2;

struct my_compact_struct
{
    my_type field1; 
    uint8_t something;
    uint16_t something_else;
};

Option A is currently implemented and seems to be working, but since I want to do (now and in the future) what's correct now and not just what's working, I was wondering if option B is clearly better.

Thanks,

Upvotes: 1

Views: 5375

Answers (4)

JOSE A VAZQUEZ
JOSE A VAZQUEZ

Reputation: 41

Step into same problem, I solved it this by using __attribute__((packed)). Packed align data to 4 Bytes, with packed (int)sizeof(my_compact_struct) = 4, without packed (int)sizeof(my_compact_struct) = 8

typedef enum __attribute__((packed)){ 
A = 0x01
B = 0x10
C = 0x255 // Max value, or any other lower than this
} my_enum;

struct my_compact_struct __attribute__((packed)){
    my_enum field1 : 8; // Forcing field to be 8 bits 
    uint8_t something;
    uint16_t something_else;
};

Upvotes: 4

StdCIsNotStd
StdCIsNotStd

Reputation: 1

You can use enum or even typedef enum like a grouped #define. Do not actually define a structure member, data stream, or global variable as type enum. Rather define all storage members as fixed types like uint8_t. As if you used #define just set them to the enum literal constants. If you use any kind of lint tool, then this design style will raise some messages which you will need to tailor. Just like malformed #define if the literal value doesn't fit, then bad things can happen, and either way you need to pay attention. In a debugger or hardware simulator, the enum can provide useful display reference information. Temporary variables are an exception to how global definitions are treated. For function parameters or automatic variables, and only then, define them with the enum type. In this context int is going to be the most efficient word size as well as the standard behavior of enum. There is no error possible nor hyper-optimizing you can do.

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234665

If your specific values in an enum can fit into a smaller type than an int, then a C implementation is free to choose the underlying type of the enum to be a smaller type than an int (but the type of the enum constants in this case will be int). But there is no way you can force a C compiler to use a type smaller than an int. So with this in mind and the fact that an int is at least 16 bits, you're out of luck.

But enums in C are little more than debugging aids. Just use an uint8_t type if you compiler has it:

static const uint8_t something = /*some value*/

If not then use a char and hope that CHAR_BIT is 8.

Upvotes: 4

dbush
dbush

Reputation: 223739

Option B would be best. You'd be defining the type in question to be a known size, and the const values you define will also be the correct size.

While you would lose out on the implicit numbering of an enum, the explicit sizing of the field and its values makes up for it.

Upvotes: 2

Related Questions