¿Son todas estas conversiones de tipo C realmente necesarias para las operaciones de registro bit a bit?

Encuentro el estilo de codificación en el STM32F0 (microcontrolador ARM Cortex-M0) SPL (biblioteca de periféricos estándar) innecesariamente detallado. Como ejemplo, aquí hay un fragmento de código para configurar el ciclo de bloqueo de fase para SYSCLK:

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;  

Donde RCC_CFGR_SWy RCC_CFGR_SW_PLLson macros para literales enteros ya convertidos a uint32_t.

#define RCC_CFGR_SW     ((uint32_t)0x00000003) 
#define RCC_CFGR_SW_PLL ((uint32_t)0x00000002)  

Y RCC->CFGRes una instancia (asignada en memoria) de una estructura del tipo

typedef struct
{
    ...
    __IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x04 */
    ...  
} RCC_TypeDef;  

Entonces, el resultado se lanzaría implícitamente de uint32_ttodos modos, incluso dando una advertencia si sucede algo divertido (a diferencia de lo que sucedería con un lanzamiento explícito).


¿Pueden eliminarse estos lanzamientos explícitos, especialmente dado que C99 garantiza (6.3.1.3) que

  • Cuando un valor con tipo entero se convierte a otro tipo entero que no sea _Bool, si el valor se puede representar con el nuevo tipo, no se modifica.

Permitiendo la simplificación del código al significativamente más claro

//Select the PLL as system clock source
RCC->CFGR &= ~(RCC_CFGR_SW);
RCC->CFGR |= RCC_CFGR_SW_PLL;  

¿O podría eso causar algunos efectos secundarios imprevistos? No estoy muy seguro, y supongo que las personas que escribieron ese código tienen más experiencia escribiendo C incrustado que yo...

Estoy haciendo esta pregunta en electronics.stackexchange en lugar de stackoverflow, ya que es bastante específico para la programación integrada de bajo nivel.

¿Puede garantizar que el resultado de todas esas expresiones sea un uint32_t? ¿Es 0x00000003 también un uint32_t? ¿Realmente quiere preocuparse de que lo sea y pensar si está garantizado o no, o quiere asegurarse de que el resultado lo esté, simplemente dígale al compilador lo que quiere que sea?
"Supongo que las personas que escribieron ese código tienen más experiencia escribiendo C incrustado que yo". Claramente, aún no tienes mucha experiencia con ST SPL: D
Creo que stackoverflow sería mejor. Esto es exactamente con lo que lidian los abogados incondicionales del lenguaje C, y ha estado lidiando desde 1989 cuando se estandarizaron todas las extrañas "conversiones enteras implícitas" del preprocesador C + tiempo de ejecución. Sin embargo, estoy seguro de que obtendrá buenas respuestas aquí también.
Eche un vistazo a las reglas de Misra para tener una idea de por qué todos esos lanzamientos pueden ser necesarios.
Tengo que estar de acuerdo con @Armandas. y estoy totalmente en desacuerdo con el Arsenal. Conozco bastante bien ANSI C y, suponiendo que RCC->CFGRtambién lo sea uint32_t, las conversiones en las dos primeras declaraciones son totalmente redundantes. hay muchos programadores de mierda que no se dan cuenta de que, además de hacer un código que funcione, también es importante hacer un código conciso, legible y fácil de mantener.
No solo los moldes, sino también los paréntesis en las dos primeras declaraciones son redundantes. A algunos programadores les gusta perder el tiempo reafirmando lo obvio. No emular.
Aunque en este caso los lanzamientos parecen redundantes, es posible que alguien estuviera a la defensiva: consulte el número 3 en lysator.liu.se/c/ten-commandments.html

Respuestas (1)

Ha pasado un tiempo desde que perdí el tiempo leyendo los estándares C. Pero hay una pista de todo eso que puede ser útil, en general. No creo que sea de mucha ayuda aquí, sin embargo. Permítanme decir lo que recuerdo y luego considerar si hay más comentarios. (Sin embargo, no estoy seguro de que este sea el lugar para buscar escritores de compiladores de C; y ellos son los que conocerían los detalles exactos).

Cuando C convierte un int con signo en un int sin signo, del mismo tamaño físico, el estándar requiere que el compilador de C produzca un resultado sin signo que (1) tenga el mismo significado de valor equivalente en el espacio de símbolos sin signo, o bien; (2) es el módulo de valor con signo 2 b i t s i z mi . Tales conversiones tienen garantizado un resultado matemático específico. Uno que la mayoría de la gente espera, de hecho. Sin embargo, cuando un int sin signo se convierte en un int con signo, nuevamente del mismo tamaño físico, el estándar requiere que si y solo si existe un significado de valor equivalente , entonces ese significado debe mantenerse. Sin embargo, si el valor sin signo excede el límite de significado de valor positivo , entonces no hay ningún resultado estándar. El compilador de C puede, supongo, generar tonterías aleatorias si así lo desea.

Puede ser que la mano izquierda no sepa lo que está haciendo la mano derecha en la codificación que está viendo. Puedes ir a mirar, por supuesto, y ver lo obvio. Pero es posible que aquellos que escriben las expresiones estén tratando de estar a la defensiva en el sentido de que alguien podría volver a escribir una constante de lo que solía ser un valor sin signo a un valor con signo (o por defecto, con signo). (A los compiladores de C se les permite, o se les permitía, hacer sus propias elecciones predeterminadas cuando el especificador firmado o no firmado estaba ausente. Y si no estaban permitidos, algunos ciertamente lo hicieron de todos modos).

Lanzar cosas a unsigned siempre garantiza un resultado específico. Así que es más seguro de usar. O lo fue una vez, cuando estaba leyendo los estándares hace años. En caso de que alguien haya usado explícitamente, o por defecto del compilador, un valor firmado.

Dicho todo esto, no puedo recordar un compilador de C que haya hecho algo loco al convertir un int sin firmar en un int con signo. En general, asumiendo que el hardware de la computadora usó la notación habitual de complemento a dos, todos hacen lo obvio y los hacen idénticos a nivel de bits. Es sólo la interpretación que cambia, más tarde. Pero eso no significa que a alguien que realmente haya leído los estándares le importe; podría decidir escribir como si hubiera un compilador de C loco por ahí. Solo para demostrar que habían leído el estándar.

Ahora, no he considerado el código que muestra en el contexto de instancias de diferentes tamaños. Pero lo anterior podría darle una pista sobre por qué está viendo esas cosas allí.