Contexto
Estamos transfiriendo el código C que se compiló originalmente usando un compilador C de 8 bits para el microcontrolador PIC. Un modismo común que se utilizó para evitar que las variables globales sin signo (por ejemplo, contadores de error) vuelvan a cero es el siguiente:
if(~counter) counter++;
El operador bit a bit aquí invierte todos los bits y la declaración solo es verdadera si counter
es menor que el valor máximo. Es importante destacar que esto funciona independientemente del tamaño variable.
Problema
Ahora estamos apuntando a un procesador ARM de 32 bits usando GCC. Hemos notado que el mismo código produce resultados diferentes. Hasta donde podemos ver, parece que la operación de complemento a nivel de bits devuelve un valor que es de un tamaño diferente al que esperaríamos. Para reproducir esto, compilamos, en GCC:
uint8_t i = 0;
int sz;
sz = sizeof(i);
printf("Size of variable: %d\n", sz); // Size of variable: 1
sz = sizeof(~i);
printf("Size of result: %d\n", sz); // Size of result: 4
En la primera línea de salida, obtenemos lo que esperaríamos: i
es 1 byte. Sin embargo, el complemento bit a bit i
es en realidad de cuatro bytes, lo que causa un problema porque las comparaciones con esto ahora no darán los resultados esperados. Por ejemplo, si está haciendo (donde i
se inicializa correctamente uint8_t
):
if(~i) i++;
Veremos i
"ajuste" desde 0xFF hasta 0x00. Este comportamiento es diferente en GCC en comparación con cuando solía funcionar como pretendíamos en el compilador anterior y el microcontrolador PIC de 8 bits.
Somos conscientes de que podemos resolver esto lanzando así:
if((uint8_t)~i) i++;
O por
if(i < 0xFF) i++;
Sin embargo, en estas dos soluciones, el tamaño de la variable debe ser conocido y es propenso a errores para el desarrollador de software. Este tipo de comprobaciones de límites superiores se producen en toda la base de código. Hay varios tamaños de variables (por ejemplo., uint16_t
Y unsigned char
etc.) y el cambio de éstos en una base de código de otra forma de trabajo no es algo que estamos deseando.
Pregunta
¿Nuestra comprensión del problema es correcta, y hay opciones disponibles para resolver esto que no requieren volver a visitar cada caso en el que hemos usado este idioma? ¿Es correcta nuestra suposición de que una operación como complemento a nivel de bits debería devolver un resultado que tenga el mismo tamaño que el operando? Parece que esto se rompería, dependiendo de las arquitecturas del procesador. Siento que estoy tomando pastillas locas y que C debería ser un poco más portátil que esto. Nuevamente, nuestra comprensión de esto podría estar equivocada.
En la superficie, esto puede no parecer un gran problema, pero este idioma que funcionaba anteriormente se usa en cientos de ubicaciones y estamos ansiosos por entender esto antes de proceder con cambios costosos.
Nota: Aquí hay una pregunta duplicada aparentemente similar pero no exacta: la operación bit a bit en char da un resultado de 32 bits
No vi el quid de la cuestión discutido allí, a saber, el tamaño del resultado de un complemento bit a bit diferente de lo que se pasa al operador.