Ich finde den Codierungsstil in der SPL (Standard-Peripheriebibliothek) des STM32F0 (ARM Cortex-M0-Mikrocontroller) unnötig ausführlich. Als Beispiel ist hier ein Codeschnipsel zum Konfigurieren des Phasenregelkreises für SYSCLK:
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
Wobei RCC_CFGR_SW
und RCC_CFGR_SW_PLL
Makros für Integer-Literale sind, die bereits in umgewandelt wurden uint32_t
.
#define RCC_CFGR_SW ((uint32_t)0x00000003)
#define RCC_CFGR_SW_PLL ((uint32_t)0x00000002)
Und RCC->CFGR
ist eine (im Speicher abgebildete) Instanz einer Struktur des Typs
typedef struct
{
...
__IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x04 */
...
} RCC_TypeDef;
Das Ergebnis würde also ohnehin implizit gecastet werden uint32_t
und sogar eine Warnung geben, wenn etwas Lustiges passiert (im Gegensatz zu dem, was bei einem expliziten Cast passieren würde).
Können diese expliziten Umwandlungen eliminiert werden, insbesondere angesichts der Tatsache, dass C99 (6.3.1.3) dies garantiert?
Ermöglicht die Vereinfachung des Codes zum deutlich Klareren
//Select the PLL as system clock source
RCC->CFGR &= ~(RCC_CFGR_SW);
RCC->CFGR |= RCC_CFGR_SW_PLL;
Oder könnte das zu unvorhergesehenen Nebenwirkungen führen? Ich bin mir nicht wirklich sicher, und ich nehme an, dass die Leute, die diesen Code geschrieben haben, mehr Erfahrung mit dem Schreiben von eingebettetem C haben als ich ...
Ich stelle diese Frage auf electronic.stackexchange anstelle von stackoverflow, da sie ziemlich spezifisch für die eingebettete Programmierung auf niedriger Ebene ist.
Es ist schon eine Weile her, dass ich Zeit damit verschwendet habe, C-Standards zu lesen. Aber es gibt einen Hinweis von all dem, was im Allgemeinen hilfreich sein kann. Ich glaube aber nicht, dass es hier eine große Hilfe ist. Lassen Sie mich sagen, woran ich mich erinnere, und dann überlegen, ob es weitere Kommentare gibt. (Ich bin mir jedoch nicht sicher, ob dies der richtige Ort ist, um nach C-Compiler-Autoren zu suchen; und sie sind diejenigen, die die genauen Details kennen.)
Wenn C eine Ganzzahl mit Vorzeichen in eine Ganzzahl ohne Vorzeichen mit der gleichen physikalischen Größe umwandelt, verlangt der Standard , dass der C-Compiler ein Ergebnis ohne Vorzeichen erzeugt, das entweder (1) die gleiche äquivalente Wertbedeutung im Zeichenraum ohne Vorzeichen hat, oder sonst; (2) ist der vorzeichenbehaftete Wert modulo . Solche Umrechnungen garantieren ein bestimmtes mathematisches Ergebnis. Eine, die die meisten Leute in der Tat erwarten. Wenn jedoch ein vorzeichenloser int in einen vorzeichenbehafteten int konvertiert wird, wiederum mit der gleichen physischen Größe, verlangt der Standard , dass genau dann, wenn es eine äquivalente Wertbedeutung gibt , diese Bedeutung beibehalten werden muss. Wenn jedoch der vorzeichenlose Wert die Grenze des positiven Werts überschreitet , gibt es überhaupt kein Standardergebnis. Der C-Compiler kann, nehme ich an, zufälligen Unsinn erzeugen, wenn er will.
Es könnte sein, dass die linke Hand nicht weiß, was die rechte Hand in der Codierung tut, die Sie sehen. Sie können natürlich hingehen und das Offensichtliche sehen. Aber es ist möglich, dass diejenigen, die die Ausdrücke schreiben, versuchen, in dem Sinne defensiv zu sein, dass jemand später eine Konstante von dem, was früher ein vorzeichenloser Wert war, in einen vorzeichenbehafteten (oder standardmäßig vorzeichenbehafteten) Wert umschreibt. (C-Compilern ist es oder war es früher gestattet, ihre eigenen Standardeinstellungen zu treffen, wenn der Bezeichner mit oder ohne Vorzeichen fehlte. Und wenn dies nicht erlaubt war, taten dies einige sicherlich trotzdem.)
Das Umwandeln von Dingen in unsigned garantiert immer ein bestimmtes Ergebnis. So ist es sicherer zu verwenden. Oder war es einmal, als ich vor Jahren die Standards las. Nur für den Fall, dass jemand explizit oder per Compiler-Standard einen signierten Wert verwendet hat.
Alles in allem kann ich mich an keinen C-Compiler erinnern, der etwas Verrücktes getan hat, als er ein unsigned int in ein signed int konvertiert hat. Unter der Annahme, dass die Computerhardware die übliche Zweierkomplementnotation verwendet, tun sie im Allgemeinen alle nur das Offensichtliche und machen sie bitweise identisch. Nur die Interpretation ändert sich später. Aber das bedeutet nicht, dass sich jemand, der die Standards tatsächlich gelesen hat, darum kümmern würde – er könnte sich entscheiden, so zu schreiben, als gäbe es da draußen einen verrückten C-Compiler. Nur um zu beweisen, dass sie den Standard gelesen haben.
Jetzt habe ich den Code, den Sie im Zusammenhang mit Instanzen unterschiedlicher Größe zeigen, nicht berücksichtigt. Aber das Obige könnte Ihnen einen Hinweis darauf geben, warum Sie solche Dinge dort sehen.
PlasmaHH
Armandas
Rohr
Arsenal
Robert Bristol-Johnson
RCC->CFGR
ist auchuint32_t
, dann sind die Umwandlungen in den ersten beiden Anweisungen völlig überflüssig. Es gibt viele beschissene Programmierer, die nicht erkennen, dass es neben der Erstellung von funktionierendem Code auch wichtig ist, den Code prägnant, lesbar und leicht zu warten.Benutzer207421
Peter Schmidt