c++c++14bit-fields

Signed bit field in C++14


I believe that until C++14 a bit field of a struct declared as int was still interpreted as either signed or unsigned, the interpretation being implementation defined. Reference: http://en.cppreference.com/w/cpp/language/bit_field.

Is this still the case in C++14? I.e., is the code below guaranteed to work as inteded?

#include <iostream>

struct X
{
    int f:3;
};

int main() 
{
    X x;
    x.f = -2; // is this going to be indeed signed? It seems so.
    std::cout << x.f << std::endl; // displays -2
}

Solution

  • According to C++11 standard §9.6/p3 Bit-fields [class.bit] (Emphasis Mine):

    A bit-field shall not be a static member. A bit-field shall have integral or enumeration type (3.9.1). It is implementation-defined whether a plain (neither explicitly signed nor unsigned) char, short, int, long, or long long bit-field is signed or unsigned. A bool value can successfully be stored in a bit-field of any nonzero size. The address-of operator & shall not be applied to a bit-field, so there are no pointers to bitfields. A non-const reference shall not be bound to a bit-field (8.5.3). [ Note: If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly. See 8.5.3. —end note ]

    So you're correct for the first part. Indeed until C++14 a bit field of a struct not specifically declared as signed was still interpreted as either signed or unsigned, the interpretation being implementation defined.

    As already mentioned in this comments by @T.C. Defect reports referring to the issue were made DR739, DR675. Resulting in the following resolutions in C++14 standard:

    The wording "It is implementation-defined whether a plain (neither explicitly signed nor unsigned) char, short, int, long, or long long bit-field is signed or unsigned.", was removed, and the C++14 wording now is:

    A bit-field shall not be a static member. A bit-field shall have integral or enumeration type (3.9.1). A bool value can successfully be stored in a bit-field of any nonzero size. The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields. A non-const reference shall not be bound to a bit-field (8.5.3). [ Note: If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly. See 8.5.3. —end note ]

    Also in §C.1.8 Clause 9: classes [diff.class] the following section was added:

    9.6

    Change: Bit-fields of type plain int are signed.

    Rationale: Leaving the choice of signedness to implementations could lead to inconsistent definitions of template specializations. For consistency, the implementation freedom was eliminated for non-dependent types, too.

    Effect on original feature: The choice is implementation-defined in C, but not so in C++.

    Difficulty of converting: Syntactic transformation.

    How widely used: Seldom.

    Consequently, in C++14 bit-fields of type plain int are signed and the code posted is guaranteed to work as intended.