Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

132
Vistas
¿Hay alguna forma de sortear esta optimización del compilador en C?

Quiero señalar que, como señaló Olaf, el compilador no tiene la culpa.


Descargo de responsabilidad: no estoy completamente seguro de que este comportamiento se deba a la optimización del compilador.

De todos modos, en C estoy tratando de determinar si el bit n (n debe estar entre 0 y 7, inclusive) de un byte de 8 bits es 1 o 0 . Inicialmente se me ocurrió esta solución:

 #include <stdint.h> #include <stdbool.h> bool one_or_zero( uint8_t t, uint8_t n ) // t is some byte, n signifies which bit { return (t << (n - (n % 8) - 1)) >> 7; }

Que, según mi comprensión previa, haría lo siguiente a un byte:

Supongamos que t = 5 y n = 2 . Entonces el byte t se puede representar como 0000 0101 . Supuse que (t << (n - (n % 8) - 1)) cambiaría los bits de t para que t sea 1010 0000 . Esta suposición es sólo parcialmente correcta. También supuse que el siguiente cambio de bit ( >> 7 ) cambiaría los bits de t para que t sea 0000 0001 . Esta suposición también es solo algo correcta.

TL;DR : Pensé que la línea return (t << (n - (n % 8) - 1)) >> 7; hice esto:

  1. t es 0000 0101
  2. Se produce el primer cambio de bit; ahora t 1010 0000
  3. Se produce el segundo cambio de bit; ahora t 0000 0001
  4. t se devuelve como 0000 0001

Aunque tengo la intención de que eso suceda, no sucede. En cambio, tengo que escribir lo siguiente para obtener los resultados esperados:

 bool one_or_zero( uint8_t t, uint8_t n ) // t is some byte, n signifies which bit { uint8_t val = (t << (n - (n % 8) - 1)); return val >> 7; }

Sé que agregar uint8_t val no es una pérdida de rendimiento masiva. Aún así, me gustaría saber dos cosas:

  1. ¿Tengo que inicializar otra variable para hacer lo que pretendo?
  2. ¿Por qué el de una sola línea no hace lo mismo que el de dos líneas?

Tengo la impresión de que cuando el compilador optimiza mi código, rompe los cambios de dos bits para que solo ocurra uno. Esto parece algo bueno, pero no "borra" los otros bits como se pretendía.

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Ese código es muy complicado solo para verificar un poco en un número entero. Pruebe el método estándar:

 return (t & (1U << n)) != 0;

Si tiene que comprobar que n es válido, agregue una afirmación. de lo contrario, el enmascaramiento (n & 7) o el módulo (n % 8) (esto será optimizado por el compilador para la operación de máscara) forzará el conteo de desplazamiento en un rango válido. Como muchos compiladores reconocerán ese patrón, podrían transformarlo en una instrucción de CPU de prueba de un solo bit, si está disponible.

Para evitar números mágicos, debe reemplazar el módulo 8 por: (sizeof(t) * CHAR_BIT) . Eso seguirá cualquier tipo que t pueda tener. La máscara es siempre uno menos que el módulo.

Tu codigo:

 (n - (n % 8) - 1))

Si n < 8 da un valor negativo ( -1 precisamente). Los cambios negativos presentan un comportamiento indefinido , por lo que cualquier cosa puede pasar (cuidado con los demonios nasales).

over 4 years ago · Santiago Trujillo Denunciar

0

Creo que eres víctima de la promoción de enteros.

Cuando tiene una expresión: x operator y hay algunas cosas que debe tener en cuenta. La primera es que el resultado (y en el proceso el otro operando) de la expresión se promociona al tipo "más grande" de los dos operandos.

En tu ejemplo, esto significa lo siguiente:

  1. (t << (n - (n % 8) - 1)) >> 7; La constante 8 es un int , por lo tanto, n%8 también es un int .
  2. (t << (n - (integer) - 1)) >> 7 (n - integer - 1) también es un número entero, lo que significa que el valor temporal (t << integer) se almacenará en un int . Esto significa que no "corta" los bits más significativos como pretende, porque el resultado se almacena en (muy probablemente) 32 bits, y no en 8 como supone.

Si, por otro lado, almacena temporalmente el resultado int en un uint8_t , cortará correctamente los bits iniciales y obtendrá lo que pretende.

Puede solucionar el problema enviando sus operandos a uint8_t durante el cálculo:

 (t << (uint8_t)(n - (n % 8) - 1))) >> 7;

O incluso mejor, use una máscara como la sugerida en la respuesta de Olaf:

 (t & ((uint8_t)1 << n)) != 0
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda