Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overflow on bitfield for signed underlying type enum

This is for C++11 only:

If I have a regular enum like below:

enum TestType
{
Test0 = 0,
Test1,
Test2,
Test3,
Test4,
Test5,
Test6,
Test7
}

and a packed struct like this:

struct
{
TestType a : 3
uint32_t b : 5
} TestStruct;

Is TestStruct.a guaranteed to be equal to any valid assigned enum value when accessed? Or is there a possibility the compiler will assign a signed underlying type and then treat the bitfield a as ranging -4 to 3.

like image 340
I.D. Avatar asked Aug 28 '18 18:08

I.D.


1 Answers

Is TestStruct.a guaranteed to be equal to its assigned enum value?

No. You default initialize TestStruct. If this is in the global space then it will be zero initialized and a and b will both be 0.

If this is in block space then no initialization happens which means a and b have an unspecified value. All you know is that the value will be in the representable range for the type. Test0 having a value of 0 does not com into play here at all.

If you had

TestStruct{};

Then a and b would be zero as you are value initializing the object and in this case that means you zero initialize it. You could also use

TestStruct{value1, value2};

to assign specific values to a and b.


For the question on if a can store all of the values of TestType we have to look at [class.bit]/4 which states

[...]If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type ([dcl.enum]), the original enumerator value and the value of the bit-field shall compare equal.

emphasis mine

and the values of the enumeration is defined by [dcl.enum]/8 as

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, for an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values in the range bmin to bmax, defined as follows: Let K be 1 for a two's complement representation and 0 for a ones' complement or sign-magnitude representation. bmax is the smallest value greater than or equal to max(|emin − K, |emax|) and equal to 2M−1, where M is a non-negative integer. bmin is zero if emin is non-negative and −(bmax+K) otherwise. The size of the smallest bit-field large enough to hold all the values of the enumeration type is max(M,1) if bmin is zero and M+1 otherwise. It is possible to define an enumeration that has values not defined by any of its enumerators. If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0

So in this case emin is 0 and emax 7 so bmin is 0 and bmax is equal to or greater than max(|emin| − K, |emax|) which is 7. Since it has to be equal to 2M−1 if we use 3 for M then we also get 7.

We have

The size of the smallest bit-field large enough to hold all the values of the enumeration type is max(M,1) if bmin is zero and M+1 otherwise.

and bmin is zero so the smallest bitfield we need is 3 which you have so you are guaranteed that all of the values of TestType will fit in a.

like image 56
NathanOliver Avatar answered Nov 04 '22 20:11

NathanOliver