Hallo, habe bei mir im C Programm beide Varianten: volatile uint8_t und uint8_t volatile Scheint beides zu funktionieren. Macht der Compiler einen Unterschied? Jens
:
Bearbeitet durch User
Nein, ist das gleiche (wie auch bei den anderen type specifiers const and restrict). Allerdings musst du bei komplexeren Typen aufpassen: "volatile char *" ist "char volatile *" und nicht "char *volatile" oder gar "char volatile *volatile".
Ist das gleiche. Google: Qualifier.
Beitrag #7575984 wurde vom Autor gelöscht.
Der Unterschied zwischen volatile uint8_t und uint8_t volatile in C liegt in der Position des Schlüsselworts volatile in der Deklaration. In beiden Fällen wird die Variable als volatile deklariert, was bedeutet, dass der Wert der Variablen sich jederzeit ändern kann, und somit der Compiler keine Annahmen über den Wert der Variablen machen sollte. Dies ist besonders wichtig bei Hardware-naher Programmierung, wie zum Beispiel bei der Arbeit mit Mikrocontrollern. Bei volatile uint8_t steht das Schlüsselwort volatile vor dem Typ (uint8_t). Bei uint8_t volatile steht es nach dem Typ. In der Praxis macht diese unterschiedliche Positionierung des volatile-Schlüsselworts jedoch keinen Unterschied in der Funktionsweise oder Bedeutung der Variable. Beide Deklarationen geben an, dass der Wert der Variablen extern beeinflusst werden kann und deshalb bei jedem Zugriff neu aus dem Speicher gelesen werden sollte. ______________________________________________________________________ __ https://ichfrage.com/frage/1229/wie-kann-ich-meine-computerperformance-verbessern#answer-1229
Isabella Z. schrieb: > Der Unterschied zwischen ... Das ist ja noch schlimmer als ChatGPT. Wer oder was produziert solch einen geistigen Dünnschiß? Oliver
Isabella Z. schrieb: > ______________________________________________________________________ > __ > https://ichfrage.com/frage/1229/wie-kann-ich-meine-computerperformance-verbessern#answer-1229 Was ist denn das für ein Klick-Fänger-Scheisse?! Ich dachte das sei die Quelle für deine Antwort und habe drauf geklickt. Verdammt. Hätte mir am Titel im Link schon auffallen müssen...
Foobar schrieb: > Nein, ist das gleiche (wie auch bei den anderen type specifiers > const > and restrict). Allerdings musst du bei komplexeren Typen aufpassen: > "volatile char *" ist "char volatile *" und nicht "char *volatile" oder > gar "char volatile *volatile". Richtig. Konkret beziehen sich alle Type-Qualifier (volatile, const, unsigned, signed) VOR dem Stern auf die "pointed-at" Variable. Alle Type Qualifier nach dem Stern beziehen sich auf den Pointer selbst.
1 | volatile char my_char_var; |
2 | volatile char * const foo = &my_char_var; |
foo ist in diesem Fall also ein const pointer auf einen volatile char. Man muss jetzt nur noch die storage qualifier im Kopf haben:
1 | static volatile char * const foo = &my_char_var; |
Das ist KEIN const pointer auf einen static volatile char, sondern ein statisch-allokierter const pointer auf ein volatile char. Das static (Storage qualifier) bezieht sich logischerweise immer auf den pointer, obwohl es vor dem Sternchen steht.
:
Bearbeitet durch User
M. N. schrieb: > Richtig. Konkret beziehen sich alle Type-Qualifier (volatile, const, > unsigned, signed) VOR dem Stern auf die "pointed-at" Variable. unsigned und signed sind keine type-qualifiers, sondern type-specifiers und haben eigene Regeln. > Alle Type Qualifier nach dem Stern beziehen sich auf den Pointer selbst. Einfach gesagt: type-qualifiers beziehen sich immer auf das, was unmittelbar links davon steht, außer wenn sie selbst ganz links stehen. Dann beziehen sie sich auf das, was unmittelbar rechts davon steht. > Man muss jetzt nur noch die storage qualifier im Kopf haben: Genau genommen heißen sie storage-class-specifier, und sie beziehen sich immer auf das Ganze.
volatile ist veraltet und sollte durch die atomic Typen bzw. Macros ersetzt werden. Der Zweck von volatile war, daß andere Instanzen die Variable auch zugreifen können und sie deshalb nicht temporär in Registern gehalten werden darf. Damit können jedoch Konflikte auftreten, wenn die Zugriffe nicht atomar erfolgen. Z.B. für read-modify-write Zugriffe (foo++) ist das ein Problem. Erst mit der atomic Kapselung ist garantiert, daß jede Instanz gültige Variablen sieht. Da atomic implizit auch volatile bedeutet, wird volatile nicht mehr benötigt und ist überflüssig.
Hallo Peter, wie wird das dann geschrieben: atomic uint8_t ? Jens
Rolf M. schrieb: > Einfach gesagt: type-qualifiers beziehen sich immer auf das, was > unmittelbar links davon steht, außer wenn sie selbst ganz links stehen. > Dann beziehen sie sich auf das, was unmittelbar rechts davon steht. Das ist eine Gruppe von Wörtern, die man in jeder Reihenfolge hinschreiben kann: storage-class-specifier, type-specifier und type-qualifier. Alles vor dem x kann man beliebig umsortieren:
1 | unsigned volatile int const short extern x; |
Man kann sich also wie du Eselsbrücken bauen, muss aber im Kopf behalten, dass es innerhalb dieser Gruppe keine echten Regeln gibt.
:
Bearbeitet durch User
Und jetzt wiederhole die Übung mal für einen Pointer ...
(prx) A. K. schrieb: > Alles vor dem x kann man beliebig umsortieren:1 unsigned > volatile int const short extern x; Alles vor dem x steht ja auch links davon, und macht daher eh kein Verständnisproblem. Oliver
Peter D. schrieb: > volatile ist veraltet und sollte durch die atomic Typen bzw. Macros > ersetzt werden. Falls atomic unterstützt wird. Und Performance ist ja auch nicht ganz unwichtig. Wenn atomic Bibliotheksfunktioe verwenden, die erst Locks allokieren um sie dann zu setzen, will man eher bei volatile bleiben.
Johann L. schrieb: > Wenn atomic > Bibliotheksfunktioe verwenden, die erst Locks allokieren um sie dann zu > setzen, will man eher bei volatile bleiben. Und legt sich damit eine Zeitbombe. Wenn man auf einem ARM eine 64Bit Variable als volatile definiert, kann der Fehler jahrelang unentdeckt bleiben. Und plötzlich steuert die Mars-Rakete ins Nirvana. Wenn der Zugriff atomar sein muß, dann ist volatile unzureichend. Man kann sich aber im Mainkontext eine Tempvariable anlegen, die bei Funktionseintritt atomar von der Interruptvariable gelesen wird und an Ende atomar rückgeschrieben wird. Dann ist der Lockingoverhead vernachlässigbar.
Peter D. schrieb: > Man kann sich aber im Mainkontext eine Tempvariable anlegen, die bei > Funktionseintritt atomar von der Interruptvariable gelesen wird und an > Ende atomar rückgeschrieben wird. Dann ist der Lockingoverhead > vernachlässigbar. Für mich persönlich ist es in dem Fall deutlich übersichtlicher, wenn ich da dann selber mit sei() und cli() hantiere. Ausserdem sehe ich so direkt den Overhead und muss nicht im Listing oder im Library-Code kontrollieren, was genau da an Overhead kommt. Der atomic-Weg hat seinen Reiz, aber überzeugt bin ich davon noch nicht. Ich sollte vielleicht mal ein kleines Projekt auf atomic umbauen um ein Urteil zu fällen.
(prx) A. K. schrieb: > Das ist eine Gruppe von Wörtern, die man in jeder Reihenfolge > hinschreiben kann: storage-class-specifier, type-specifier und > type-qualifier. Und function-specifier. > Man kann sich also wie du Eselsbrücken bauen, muss aber im Kopf > behalten, dass es innerhalb dieser Gruppe keine echten Regeln gibt. Die Eselsbrücke dient dafür, um zu wissen, auf was ein type-qualifier wirkt, wenn Zeiger-Typen involviert sind. Das sind sie in deinem Beispiel aber nicht.
:
Bearbeitet durch User
Peter D. schrieb: > Wenn der Zugriff atomar sein muß, dann ist volatile unzureichend. Ja, nur ist und war das schon immer so. Wer also bei einer Marsrakete oder auch sonst wo einen 64-Bit Variable volatile statt atomic definiert, macht halt einen Fehler. Das macht volatile nicht veraltet, man muß es wie atomic oder alles andere überhaupt nur richtig anwenden. Im o.a. Fall eines volatile uint8_t brauchts kein atomic. Oliver
Peter D. schrieb: > Wenn der Zugriff atomar sein muß, dann ist volatile unzureichend. Ich hab ja auch nix anderes behauptet. Aber __atomic_load zu verwenden wenn nix dahinter ist, ist bestimmt keine so gute Idee. Und sei/cli oder ATOMIC_BLOCK sind ja kein Hexenwerk, und wenn man wirklich AVR → XYZ portiert, fällt das ja auf. Bare Metal mit sher begrenzten Resources UND Compiler-Unterstützung ist eben nicht ganz die Liga von Boliden... Und dass Interrupt-Sperren auf Multi-Core Systemen nix bringen (man kann ja schwerlich erst mal alle anderen Cores anhalten etc.) ist auch klar. ...und wenn man sowas wie __atomic_load z.B. im avr-gcc unterstützt, würde man das auch in IRQ-Sperre klammern; um die Latenz käme ma also auch dann nicht drumrum.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.