¿Por qué un int sin signo de campo de bits se convierte en un int firmado después de la operación de cambio en C ++? [duplicar]

Dec 15 2020

El código de prueba:

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

El resultado es:, -65536y el tipo de bes intpero no uint32_t.

Descubrí que, uint16_ty uint8_ttambién se firmará int después del operador de turno, y hubo una pregunta similar en C#, que llegó a la conclusión de que el resultado se firmaría cuando el operando sea <32 bits. ¿Por qué las operaciones de desplazamiento siempre dan como resultado un int con signo cuando el operando es <32 bits?

Pero el tipo de a.loes claramente uint32_t, lo que se puede verificar decltype(a.lo), entonces, ¿cómo se puede explicar esto?

Respuestas

7 StoryTeller-UnslanderMonica Dec 15 2020 at 20:01

Forma parte de la promoción integral estándar.

[expr.shift]

1 Los operadores de turno <<y el >>grupo de izquierda a derecha

Los operandos serán de tipo enumeración integral o sin ámbito y se realizarán promociones integrales. El tipo de resultado es el del operando izquierdo promovido.

[conv.prom]

5 Un prvalue para un campo de bits integral ([class.bit]) se puede convertir en un prvalue de tipo intsi intpuede representar todos los valores del campo de bits; de lo contrario, se puede convertir a unsigned intsi unsigned intpuede representar todos los valores del campo de bits. Si el campo de bits es aún mayor, no se le aplica ninguna promoción integral. Si el campo de bits tiene un tipo enumerado, se trata como cualquier otro valor de ese tipo para fines de promoción.

La promoción de su operando izquierdo (el campo de bits) produce un int, y ese es el tipo de toda la expresión de desplazamiento. Por blo tanto, también es una intdeducción por tipo de marcador de posición.