Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

130
Views
¿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 answers
Answer question

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!