Sind all diese C-Type-Casts wirklich für bitweise Registeroperationen notwendig?

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_SWund RCC_CFGR_SW_PLLMakros 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->CFGRist 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_tund 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?

  • Wenn ein Wert mit ganzzahligem Typ in einen anderen ganzzahligen Typ als _Bool konvertiert wird und der Wert durch den neuen Typ dargestellt werden kann, bleibt er unverändert.

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.

Können Sie garantieren, dass das Ergebnis all dieser Ausdrücke ein uint32_t ist? ist 0x00000003 auch ein uint32_t? Wollen Sie sich wirklich Sorgen machen, dass es so ist, und darüber nachdenken, ob es garantiert ist oder nicht, oder wollen Sie sicherstellen, dass das Ergebnis so ist, also sagen Sie einfach dem Compiler, dass Sie es haben wollen?
"Ich nehme an, dass die Leute, die diesen Code geschrieben haben, mehr Erfahrung mit dem Schreiben von eingebettetem C haben als ich." Offensichtlich haben Sie noch nicht viel Erfahrung mit ST-SPLs: D
Ich denke, Stackoverflow wäre besser. Das ist genau das, womit sich die eingefleischten Anwälte der C-Sprache befassen, und zwar seit 1989, als all die seltsamen C-Präprozessor-Laufzeit-„impliziten Integer-Konvertierungen“ standardisiert wurden. Ich bin mir sicher, dass du auch hier gute Antworten bekommen wirst.
Werfen Sie einen Blick auf die Misra-Regeln, um ein Gefühl dafür zu bekommen, warum all diese Würfe notwendig sein könnten.
Ich muss @Armandas zustimmen. und ich bin völlig anderer Meinung als Arsenal. Ich kenne gerade ANSI C ziemlich gut und vorausgesetzt, das RCC->CFGRist auch uint32_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.
Nicht nur die Umwandlungen, sondern auch die Klammern in den ersten beiden Anweisungen sind überflüssig. Einige Programmierer verschwenden gerne ihre Zeit damit, das Offensichtliche zu wiederholen. Nicht emulieren.
Obwohl die Zauber in diesem Fall überflüssig erscheinen, ist es möglich, dass jemand defensiv war: Siehe Nummer 3 unter lysator.liu.se/c/ten-commandments.html

Antworten (1)

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 2 B ich T S ich z e . 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.