3

I'd like to define an enum to be smaller than one byte while maintaining type safety.

Defining an enum as:

enum MyEnum : unsigned char
{
    i ,j, k, w
};

I can shrink it to one byte, however I'd like to make it use only 2 bits since I will at most have 4 values in it. Can this be done?

In my struct where I use the enum, the following does not work

struct MyStruct
{
    MyEnum mEnum : 2; // This will be 4 bytes in size
};

Thanks!

Update:

The questions comes from this scenario:

enum MyEnum : unsigned char
{
    i ,j, k, w
};

struct MyStruct
{
    union
    {
        signed int mXa:3;
        unsigned int mXb:3;
    };

    union
    {
        signed int mYa:3;
        unsigned int mYb:3;
    };

    MyEnum mEnum:2;
};

sizeof(MyStruct) is showing 9 bytes. Ideally I'd like the struct to be 1 bytes in size.

Update for implemented solution:

This struct is one byte and offers the same functionality and type safety:

enum MyEnum :unsigned char
{
   i,j,k,w
};

struct MyStruct
{
   union
   {
      struct { MyEnum mEnum:2; char mXa:3; char mXb:3;};
      struct { MyEnum mEnum:2; unsigned char mYa:3; unsigned char mYb:3;};
   }; 
};
mrantifreeze
  • 65
  • 1
  • 7
  • 4
    Nope. The best option is to use bit fields, but in C++, nothing less than a byte is addressable per se. –  Jun 11 '13 at 21:00
  • What exactly are you trying to solve? Giving some context might help reveal either a design flaw or a better solution. – Vite Falcon Jun 11 '13 at 21:27
  • I'm trying to shrink the struct as much as possible for a challenge and I don't see why it can't be done so the struct is no larger than 1 byte. – mrantifreeze Jun 11 '13 at 23:13

4 Answers4

5

As per standard definition, a types sizeof must be at least 1 byte. This is the smallest addressable unit of memory.

The feature of bitfields you are mentioning allows to define members of structures to have smaller sizes, but the struct itself may not be because

  • It must be of at least 1 byte too
  • Alignment considerations might need it to be even bigger

additionally you may not take the address of bitfield members, since as said above, a byte is the smallest addressable unit of memory (You can already see that by sizeofactually returning the number of bytes, not bits, so if you expected less than CHAR_BIT bits, sizeof would not even be able to express it).

PlasmaHH
  • 15,673
  • 5
  • 44
  • 57
  • Certainly, but I'm not quite sure why when (in my updated question) now that the enum is a member of a bit packed struct, the size inflated drastically. – mrantifreeze Jun 11 '13 at 21:17
  • @mrantifreeze: I don't know what you exactly mean by "bit packed struct" but maybe you are looking for compiler extensions like gccs `[[packed]]` attribute? I would assume that most compilers gave the unions the alignment requirements of unsigned/signed, and that would make the padding to 3 times unsigned = 12 bytes on those. – PlasmaHH Jun 11 '13 at 21:26
  • @PlasmaHH: Careful, his unions have a `sizeof(4)`, but an alignment of only 1 :D – Mooing Duck Jun 11 '13 at 21:42
1

No. C++ defines "char" to be the smallest addressable unit of memory for the platform. You can't address 2 bits.

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
1

bitfields can only share space if they use the same underlying type. And any unused bits are actually left unused; if the sum of bits in an unsigned int bitfield is 3 bits, it still takes 4 bytes total. Since both enums have unsigned int members, they're both 4 bytes, but since they are bitfields, they have an alignment of one. So the first enum is 4 bytes, and the second is four bytes, then the MyEnum is 1 byte. Since all of those have an alignment of one, no padding is needed.

Unfortunately, union doesn't really work with bitfields really at all. Bitfields are for integer types only. The most I could get your data to without serious redesign is 3 bytes: http://coliru.stacked-crooked.com/view?id=c6ad03c93d7893ca2095fabc7f72ca48-e54ee7a04e4b807da0930236d4cc94dc

enum MyEnum : unsigned char
{
    i ,j, k, w
};

union MyUnion
{
    signed char ma:3; //char to save memory
    unsigned char mb:3;
};

struct MyStruct
{
    MyUnion X;
    MyUnion Y; 
    MyEnum mEnum;
}; //this structure is three bytes

In the complete redesign category, you have this: http://coliru.stacked-crooked.com/view?id=58269eef03981e5c219bf86167972906-e54ee7a04e4b807da0930236d4cc94dc

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
0

Bit packing 'Works for me'

#include <iostream>

enum MyEnum : unsigned char
{
    i ,j, k, w
};
struct MyStruct
{
    MyEnum mEnum : 2;
    unsigned char val : 6;
};

int main()
{
    std::cout << sizeof(MyStruct);
}

prints out 1. How / what are you measuring?

Edit: Live link

Are you doing something like having a pointer as the next thing in the struct? In which case, you'll have 30bits of dead space as pointers must be 4 byte aligned on most 32bit systems.

Edit: With your updated example, its the unions which are breaking you

enum MyEnum : unsigned char
{
    i ,j, k, w
};


struct MyStruct
{
    unsigned char mXb:3;
    unsigned char mYb:3;

    MyEnum mEnum:2;
};

Has size 1. I'm not sure how unions and bit packing work together though, so I'm no more help.

Mike Vine
  • 9,468
  • 25
  • 44
  • bit packing only works with integral types. unions are not integral types. So sadly, they _don't work togeather at all_. :( – Mooing Duck Jun 11 '13 at 21:43