Dlaczego niepodpisane int z pola bitowego staje się int ze znakiem po operacji zmiany w C ++? [duplikować]

Dec 15 2020

Kod testu:

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;
}

Dane wyjściowe to:, -65536a typ bto, intale nie uint32_t.

Stwierdziłem, że uint16_ti uint8_tpo operatorze zmiany zostanie również podpisany int, i było podobne pytanie w C#, w którym doszedłem do wniosku, że wynik zostałby podpisany, gdy operand jest <32 bitów. Dlaczego operacje przesunięcia zawsze skutkują znakiem int, gdy operand jest <32 bitów

Ale rodzaj a.lojest wyraźnie uint32_t, co można zweryfikować decltype(a.lo), więc jak to wyjaśnić?

Odpowiedzi

7 StoryTeller-UnslanderMonica Dec 15 2020 at 20:01

To część standardowej promocji integralnej.

[wyr.shift]

1 Operatory zmiany <<i >>grupują od lewej do prawej

Operandy powinny być typu wyliczeniowego integralnego lub nieograniczonego i wykonywane są promocje integralne. Typ wyniku to promowany lewy operand.

[konw.prom]

5 Wartość pr dla integralnego pola bitowego ([class.bit]) można przekonwertować na wartość typu prvalue, intjeśli intmoże reprezentować wszystkie wartości pola bitowego; w przeciwnym razie można go przekonwertować na unsigned intif unsigned intmoże reprezentować wszystkie wartości pola bitowego. Jeśli pole bitowe jest jeszcze większe, nie stosuje się do niego żadnej promocji integralnej. Jeśli pole bitowe ma typ wyliczeniowy, jest traktowane jako każda inna wartość tego typu do celów promocyjnych.

Promocja twojego lewego operandu (pola bitowego) daje wynik int, więc jest to typ całego wyrażenia shift. Tak bjest intteż odliczenie typu zastępczego.