4

Should the use of int-type bit-fields be discouraged?

 2 years ago
source link: https://www.codesd.com/item/should-the-use-of-int-type-bit-fields-be-discouraged.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Should the use of int-type bit-fields be discouraged?

advertisements

From the Draft C++ Standard (N3337):

9.6 Bit-fields

4 If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. 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 (7.2), the original enumerator value and the value of the bit-field shall compare equal.

The standard is non-committal about any such behavior for bit-fields of other types. To understand how g++ (4.7.3) deals with other types of bit-fields, I used the following test program:

#include <iostream>

enum TestEnum
{
   V1 = 0,
   V2
};

struct Foo
{
   bool          d1:1;
   TestEnum      d2:1;
   int           d3:1;
   unsigned int  d4:1;
};

int main()
{
   Foo foo;
   foo.d1 = true;
   foo.d2 = V2;
   foo.d3 = 1;
   foo.d4 = 1;

   std::cout << std::boolalpha;

   std::cout << "d1: " << foo.d1 << std::endl;
   std::cout << "d2: " << foo.d2 << std::endl;
   std::cout << "d3: " << foo.d3 << std::endl;
   std::cout << "d4: " << foo.d4 << std::endl;
   std::cout << std::endl;

   std::cout << (foo.d1 == true) << std::endl;
   std::cout << (foo.d2 == V2) << std::endl;
   std::cout << (foo.d3 == 1) << std::endl;
   std::cout << (foo.d4 == 1) << std::endl;

   return 0;
}

The output:

d1: true
d2: 1
d3: -1
d4: 1

true
true
false
true

I was surprised by the lines of the output corresponding to Foo::d3. The output is the same at ideone.com.

Since the standard is non-committal about the comparision of bit-fields of type int, g++ does not seem to be in violation of the standard. That brings me to my questions.

Is use of bit-fields of type int a bad idea? Should it be discouraged?


Yes, bit fields of type int are a bad idea, because their signedness is implementation-defined. Use signed int or unsigned int instead.

For non-bitfield declarations, the type name int is exactly equivalent to signed int (or int signed, or signed). The same pattern is followed for short, long, and long long: the unadorned type name is the signed version, and you have to add the unsigned keyword to name the corresponding unsigned type.

Bit fields, for historical reasons, are a special case. A bit-field defined with the type int is equivalent either to the same declaration with signed int, or to the same declaration with unsigned int. The choice is implementation-defined (i.e., it's up to the compiler, not to the programmer). A bit field is the only context in which int and signed int aren't (necessarily) synonymous. The same applies to char, short, long, and long long.

Quoting the C++11 standard, section 9.6 [class.bit]:

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.

(I'm not entirely sure of the rationale for this. Very old versions of C didn't have the unsigned keyword, and unsigned bit fields are usually more useful than signed bit fields. It may be that some early C compilers implemented bit fields before the unsigned keyword was introduced. Making bit fields unsigned by default, even when declared as int, may have been just a matter of convenience. There's no real reason to keep the rule other than to avoid breaking old code.)

Most bit fields are intended to be unsigned, which of course means that they should be defined that way.

If you want a signed bit field (say, a 4-bit field that can represent values from -8 to +7, or from -7 to +7 on a non-two's-complement system), then you should explicitly define it as signed int. If you define it as int, then some compilers will treat it as unsigned int.

If you don't care whether your bit field is signed or unsigned, then you can define it as int -- but if you're defining a bit field, then you almost certainly do care whether it's signed or unsigned.

Tags bit-fields

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK