The test code:
struct A
{
uint32_t lo : 16;
uint32_t hi : 16;
};
int main()
{
A a{};
a.lo = 0xFFFF;
auto b = a.lo << 16;
cout << b << endl;
return 0;
}
The output is:-65536
, and the type of b
is int
but not uint32_t
.
I have found that, uint16_t
and uint8_t
will also become signed int after shift operator, and there was a similar question in C#
, which came to the conclusion that the result would become signed when the operand is <32 bits.
Why do shift operations always result in a signed int when operand is <32 bits
But the type of a.lo
is clearly uint32_t
, which can be verified by decltype(a.lo)
, so how can this be explained?
In C, we can specify size (in bits) of structure and union members. The idea is to use memory efficiently when we know that the value of a field or group of fields will never exceed a limit or is within a small range. For example, consider the following declaration of date without the use of bit fields.
An int is signed by default, meaning it can represent both positive and negative values. An unsigned is an integer that can never be negative.
Generally, the smallest addressable chunk of data in C is a byte. You can not have a pointer to a bit, so you can not declare a variable of 1 bit size. But as Sourav Ghosh already pointed out, you can declare bitfields, where one bit is accessed directly.
Bit fields can be used to reduce memory consumption when a program requires a number of integer variables which always will have low values. For example, in many systems storing an integer value requires two bytes (16-bits) of memory; sometimes the values to be stored actually need only one or two bits.
It's part of the standard integral promotion.
[expr.shift]
1 The shift operators
<<
and>>
group left-to-rightThe operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand.
[conv.prom]
5 A prvalue for an integral bit-field ([class.bit]) can be converted to a prvalue of type
int
ifint
can represent all the values of the bit-field; otherwise, it can be converted tounsigned int
ifunsigned int
can represent all the values of the bit-field. If the bit-field is larger yet, no integral promotion applies to it. If the bit-field has an enumerated type, it is treated as any other value of that type for promotion purposes.
Promotion of your left operand (the bit-field) produces an int
, and so that's the type of the entire shift expression. Thus b
is an int
too by placeholder type deduction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With