"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > ¿Por qué el operador de desplazamiento a la derecha (`>>`) en C++ produce resultados inesperados al realizar un desplazamiento de 32 bits?

¿Por qué el operador de desplazamiento a la derecha (`>>`) en C++ produce resultados inesperados al realizar un desplazamiento de 32 bits?

Publicado el 2024-11-01
Navegar:802

Why does the right shift operator (`>>`) en C produce resultados inesperados al cambiar 32 bits?
>`) en C produce resultados inesperados al cambiar 32 bits. " />

Comportamiento inesperado del operador de desplazamiento a la derecha (1 >> 32)

En el ámbito de la programación, el operador de desplazamiento a la derecha (>>) se usa comúnmente para realizar operaciones bit a bit, particularmente para dividir un número entero por una potencia de dos. Sin embargo, puede surgir un comportamiento peculiar al realizar cambios en valores más grandes, como lo demuestra el siguiente código C:

int foo(int a, int b) {
   return a >> b;
}

int bar(uint64_t a, int b) {
   return a >> b;
}

int main() {
    std::cout > 32: " > 32) > (int)32: " > (int)32) 

Sorprendentemente, el resultado de este programa revela resultados inesperados:

foo(1, 32): 1 // Should be 0
bar(1, 32): 0
1 >> 32: 0
(int)1 >> (int)32: 0

La lógica detrás de estos resultados radica en el funcionamiento interno de la CPU y el compilador.

Comportamiento de la función foo()

En la función foo(), la operación de desplazamiento se realiza sin conversión, lo que lleva a la CPU a realizar un desplazamiento lógico a la derecha. En muchas arquitecturas, el desplazamiento lógico a la derecha se implementa como a >> (b % 32), ignorando efectivamente los bits superiores de b. Por lo tanto, foo(1, 32) da como resultado 1 >> (32 % 32), que se evalúa como 1 >> 0, lo que produce 1.

¿Por qué es importante la conversión a enteros de 64 bits?

En la función bar(), se proporciona un entero sin signo de 64 bits, lo que garantiza que el resultado sea 0 porque b (32) es menor que el número de bits en el operando (64 ). Sin embargo, cuando b se cambia a 64, el resultado se vuelve impredecible y aún puede producir 1.

Optimización del compilador

En el caso de 1 >> 32 y (int )1 >> (int)32, el compilador optimiza estas expresiones constantes en tiempo de compilación. El estándar especifica un comportamiento indefinido para desplazamientos a la derecha donde el recuento es negativo o mayor o igual a la longitud del operando. Dado que 32 excede la longitud del operando, el compilador no puede determinar el resultado y genera 0 como alternativa segura.

Comportamiento específico de la CPU

La implementación del desplazamiento a la derecha Las operaciones pueden variar entre diferentes CPU. En arquitecturas x86/x86-64, el desplazamiento lógico a la derecha es efectivamente a >> (b % 32 o 64), según el modo. Sin embargo, en los procesadores ARM, la operación de turno correcto garantiza cero para turnos mayores o iguales a 32.

Conclusión

Cuando se trabaja con operadores de turno correcto, es esencial para considerar posibles comportamientos indefinidos, especialmente cuando el recuento de turnos excede la longitud del operando. La conversión a tipos de enteros más amplios, como enteros de 64 bits, puede garantizar resultados consistentes en diferentes CPU y compiladores.

Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3