¿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]
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:, -65536
y el tipo de b
es int
pero no uint32_t
.
Descubrí que, uint16_t
y uint8_t
tambié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.lo
es claramente uint32_t
, lo que se puede verificar decltype(a.lo)
, entonces, ¿cómo se puede explicar esto?
Respuestas
Forma parte de la promoción integral estándar.
[expr.shift]
1 Los operadores de turno
<<
y el>>
grupo de izquierda a derechaLos 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
int
siint
puede representar todos los valores del campo de bits; de lo contrario, se puede convertir aunsigned int
siunsigned int
puede 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 b
lo tanto, también es una int
deducción por tipo de marcador de posición.