Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does an unsigned int of bit-field become a signed int after shift operation in C++? [duplicate]

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?

like image 220
xxhxx Avatar asked Dec 15 '20 12:12

xxhxx


People also ask

How bitfields works in C?

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.

Is int default signed or unsigned?

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.

How to declare a bit in C?

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.

Why bit fields used in structures?

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.


1 Answers

It's part of the standard integral promotion.

[expr.shift]

1 The shift operators << and >> group left-to-right

The 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 if int can represent all the values of the bit-field; otherwise, it can be converted to unsigned int if unsigned 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.

like image 58
StoryTeller - Unslander Monica Avatar answered Oct 06 '22 21:10

StoryTeller - Unslander Monica