¿Son todos estos modelos de tipo C realmente necesarios para las operaciones de registro a nivel de bit?

1

Encuentro el estilo de codificación en el STM32F0 (microcontrolador ARM Cortex-M0) SPL (biblioteca de periféricos estándar) innecesariamente detallado. A modo de ejemplo, aquí hay un fragmento de código para configurar el bucle de fase bloqueada 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_SW y RCC_CFGR_SW_PLL son 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->CFGR es 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;  

Por lo tanto, el resultado se emitirá implícitamente a uint32_t de todos modos, incluso dará una advertencia si ocurre algo gracioso (a diferencia de lo que sucedería con un reparto explícito).

¿Se pueden eliminar estos lanzamientos explícitos, especialmente dado que C99 garantiza (6.3.1.3) que

  • Cuando un valor con tipo entero se convierte en otro tipo entero distinto de _Bool, si el valor puede representarse por el nuevo tipo, no se modifica.

Permitir la simplificación del código para que sea 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 causar algunos efectos secundarios imprevistos? No estoy seguro, y supongo que las personas que escribieron ese código tienen más experiencia en la escritura de C incrustada 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.

    
pregunta jms

1 respuesta

2

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

Cuando C convierte un int firmado 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 equivalente valor significado en el espacio de símbolo sin signo, o bien; (2) es el valor con signo módulo \ $ 2 ^ {bitsize} \ $. 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 firmado, nuevamente del mismo tamaño físico, el estándar requiere que si y solo si existe un valor equivalente significado , entonces ese significado debe mantenerse. Sin embargo, si el valor sin firmar supera el límite del significado positivo , entonces no hay un resultado estándar, en absoluto. El compilador de C puede, supongo, generar tonterías aleatorias si quiere.

Podría ser que la mano izquierda no sepa lo que hace 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 ser defensivos en el sentido de que alguien pueda volver a escribir una constante desde lo que solía ser un valor sin signo a un firmado (o por defecto, firmado) valor. (A los compiladores de C se les permite, o solían estarlo, hacer sus propias elecciones predeterminadas cuando el especificador signed o unsigned estaba ausente. Y si no estaban permitidos, algunos ciertamente lo hizo de todos modos.)

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

Dicho todo esto, no puedo recordar un compilador de C que hizo una locura al convertir un int sin signo en un int firmado. En general, asumiendo que el hardware de la computadora usó la notación habitual del complemento de dos, todos ellos simplemente hacen lo obvio y los hacen en el modo de bits idénticos. Es sólo la interpretación que cambia, más tarde. Pero eso no significa que a una persona que realmente haya leído los estándares le importe, puede que decida escribir como si hubiera un compilador de C loco. Solo para probar que habían leído el estándar.

Ahora, no he considerado el código que se muestra en el contexto de instancias de diferentes tamaños. Pero lo anterior puede darte una idea de por qué estás viendo esas cosas allí.

    
respondido por el jonk

Lea otras preguntas en las etiquetas