Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this warning related to enum class size wrong?

Tags:

c++

enums

gcc

c++11

Warning:

src/BoardRep.h:49:12: warning: ‘BoardRep::BoardRep::Row::<anonymous struct>::a’ 
is too small to hold all values of ‘enum class BoardRep::Piece’ 
[enabled by default]
Piece a:2;
        ^

Enum:

enum class Piece: unsigned char {
    EMPTY,
    WHITE,
    BLACK
};

Use:

union Row {
    struct {
        Piece a:2;
        Piece b:2;
        Piece c:2;
        Piece d:2;
        Piece e:2;
        Piece f:2;
        Piece g:2;
        Piece h:2;
    };
    unsigned short raw;
};

With an enum I'd agree with GCC, it may have to truncate but that's because enums are not really separate from integers and pre-processor definitions. However an enum class is much stronger. If it is not strong enough to assume ALL Piece values taken as integers will be between 0 and 2 inclusive then the warning makes sense. Otherwise GCC is being needlessly picky and it might be worth mailing the list to say "look, this is a silly warning"

Incase anyone cannot see the point

You can store 4 distinct values in 2 bits of data, I only need 3 distinct values, so any enum of length 4 or less should fit nicely in the 2 bits given (and my enum does "derive" (better term?) from an unsigned type). If I had 5 or more THEN I'd expect a warning.

like image 944
Alec Teal Avatar asked Mar 24 '14 10:03

Alec Teal


2 Answers

The warning issued by gcc is accurate, there's no need to compose a mail to the mailing list asking them to make the warning less likely to appear.

The standard says that an enumeration with the underlying type of unsigned char cannot be represented by a bitfield of length 2; even if there are no enumerations that holds such value.


THE STANDARD

The underlying value of an enumeration is valid even if there are no enum-keys corresponding to this value, the standard only says that a legal value to be stored inside an enumeration must fit inside the underlying type; it doesn't state that such value must be present among the enum-keys.

7.2 Enumeration declarations [dcl.enum]

7... It is possible to define an enumeration that has values not defined by any of its enumerators. ...


Note: the quoted section is present in both C++11, and the draft of C++14.

Note: wording stating the same thing, but using different terminology, can be found in C++03 under [dcl.enum]p6

Note: the entire [decl.enum]p7 hasn't been included to preserve space in this post.


DETAILS

enum class E : unsigned char { A, B, C };

E x = static_cast<E> (10);

Above we initialize x to store the value 10, even if there's no enumeration-key present in the enum-declaration of enum class E this is still a valid construct.

With the above in mind we easily deduce that 10 cannot be stored in a bit-field of length 2, so the warning by gcc is nothing but accurate.. we are potentially trying to store values in our bit-field that it cannot represent.


EXAMPLE

enum class E : unsigned char { A, B, C };

struct A {
  E value : 2;
};

A val;

val.value = static_cast<E> (10); // OMG, OPS!?
like image 163
Filip Roséen - refp Avatar answered Oct 20 '22 00:10

Filip Roséen - refp


According to the C++ Standard

8 For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.

So the values of your enumeration are in the range

std::numeric_limits<unsigned char>::min() - std::numeric_limits<unsigned char>::max()

Bit field a defined as

Piece a:2;

can not hold all values of the enumeration.

If you would define an unscoped enumeration without a fixed underlying type then the range of its values would be

0 - 2
like image 33
Vlad from Moscow Avatar answered Oct 19 '22 23:10

Vlad from Moscow