c++ gcc assembly standards undefined-behavior

c++ - ¿Es correcto cambiar el comportamiento indefinido si el recuento es más grande que el ancho del tipo?



gcc assembly (2)

Acabo de comprobar el estándar de C ++ . Parece que el siguiente código NO debe ser un comportamiento indefinido :

unsigned int val = 0x0FFFFFFF; unsigned int res = val >> 34; // res should be 0 by C++ standard, // but GCC gives warning and res is 67108863

Y del estándar:

El valor de E1 >> E2 es E1 posiciones de bit E2 desplazadas a la derecha. Si E1 tiene un tipo sin signo o si E1 tiene un tipo firmado y un valor no negativo, el valor del resultado es la parte integral del cociente de E1 / 2 ^ E2. Si E1 tiene un tipo firmado y un valor negativo, el valor resultante está definido por la implementación.

De acuerdo con el estándar, dado que 34 NO es un número negativo, la variable res será 0.

GCC da la siguiente advertencia para el fragmento de código, y res es 67108863 :

advertencia: cuenta de desplazamiento a la derecha> = ancho de tipo

También verifiqué el código de ensamblaje emitido por GCC. Simplemente llama a SHRL y al documento de instrucciones de Intel para SHRL, la res no es CERO.

Entonces, ¿eso significa que GCC no implementa el comportamiento estándar en la plataforma Intel?


El borrador del estándar de C ++ en la sección 5.8 Operadores de cambio en el párrafo 1 dice ( énfasis mío ):

El tipo de resultado es el del operando izquierdo promovido. El comportamiento no está definido si el operando derecho es negativo, o mayor o igual que la longitud en bits del operando izquierdo promovido .

Entonces, si unsigned int es de 32 bits o menos, esto no está definido, que es exactamente la advertencia que te está dando gcc .


Para explicar exactamente lo que sucede: el compilador cargará 34 en un registro, y luego su constante en otro registro, y realizará una operación de cambio a la derecha con esos dos registros. El procesador x86 realiza un "shiftcount% bits" en el valor de desplazamiento, lo que significa que obtiene un desplazamiento a la derecha en 2.

Y desde 0x0FFFFFFF (268435455 decimal) dividido por 4 = 67108863, ese es el resultado que ves.

Si tuviera un procesador diferente, por ejemplo, un PowerPC (creo), bien podría darle cero.