2009-11-24 3 views
6

Tut mir leid, wenn das einfach ist, ist mein C++ rostig.leicht komisch C++ Code

Was macht das? Soweit ich sehen kann, gibt es keine Zuweisung oder Funktionsaufruf. Dieses Codemuster wird in einem Code, den ich geerbt habe, mehrmals wiederholt. Wenn es darauf ankommt, ist es eingebetteter Code.

edit: weiter von dort, bestätigt der folgende Code Heide Verdacht? (Genau von Code, einschließlich der Wiederholung, mit Ausnahme der Namen wurden geändert, um die Unschuldigen zu schützen)

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X; 

*(volatile UINT16 *)& someVar->something; 

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X; 

*(volatile UINT16 *)& someVar->something; 
x = SomeData; 
+1

Eingebetteter Code? Dann ist dies wahrscheinlich eine physische Adresse, wie Sharth vermutete. –

+0

Hinweis Ich hatte einen Link zum Artikel in der Antwort unten hinzugefügt: http://www.mjmwired.net/kernel/Documentation/volatile-consided-harmful.txt – Artyom

+0

Es ist eine gute Idee, das Ergebnis eines Lesevorgangs zu werfen, der nirgends hinführt mit '(void)', um Compiler-Warnungen zu vermeiden. Also '(void) * (flüchtig uint16_t *) & etwasVar-> etwas'. Natürlich, wickeln Sie dies in eine Makro- oder Inline-Funktion, schneiden und fügen Sie diese nicht überall ein! –

Antwort

19

Dies ist ein ziemlich allgemeines Idiom in Embedded-Programmierung (obwohl es in einer Reihe von Funktionen oder Makros verkapselt werden sollte), auf die auf ein Geräteregister zugegriffen werden muss. In vielen Architekturen sind Geräteregister auf eine Speicheradresse abgebildet und werden wie jede andere Variable angesprochen (obwohl an einer festen Adresse - entweder Zeiger verwendet werden können oder der Linker oder eine Compiler-Erweiterung bei der Festlegung der Adresse helfen kann).Wenn der C-Compiler jedoch keinen Nebeneffekt für einen Variablenzugriff sieht, kann er ihn optimieren - es sei denn, die Variable (oder der für den Zugriff auf die Variable verwendete Zeiger) wird als flüchtig markiert.

So der Ausdruck;

*(volatile UINT16 *)&someVar->something; 

wird ein 16-Bit auf einig OFFSET READ Ausgabe (vom something Strukturelement des Offset) von der Adresse in dem Zeiger someVar gespeichert. Dieser Lesevorgang wird ausgeführt und kann vom Compiler aufgrund des Schlüsselworts nicht optimiert werden.

Beachten Sie, dass einige Geräteregister einige Funktionen ausführen, selbst wenn sie nur gelesen werden - auch wenn die gelesenen Daten nicht anderweitig verwendet werden. Dies ist durchaus üblich bei Statusregistern, bei denen eine Fehlerbedingung nach dem Lesen des Registers, das den Fehlerzustand in einem bestimmten Bit anzeigt, gelöscht werden kann.

Dies ist wahrscheinlich einer der häufigsten Gründe für die Verwendung des Schlüsselwortes volatile.

+0

Danke, markiert diese als Antwort, weil ich denke, es ist die klarste und vollständigste Antwort. –

9

Ich denke, die Absicht des Autors war der Compiler zu verursachen Speicherbarrieren an diesen Punkten zu emittieren. Durch Auswertung des Ausdrucksergebnisses einer flüchtigen Komponente wird dem Compiler angezeigt, dass dieser Ausdruck nicht wegoptimiert werden sollte und die Semantik des Zugriffs auf einen flüchtigen Ort (Speicherbarrieren, Optimierungseinschränkungen) in jeder Zeile "instanziieren" sollte wo dieses Idiom auftritt.

Diese Art von Idiom könnte in einem Makro vor dem Prozessor (#define) "eingekapselt" werden, falls eine andere Kompilierung eine andere Möglichkeit hat, den gleichen Effekt zu verursachen. Zum Beispiel könnte ein Compiler mit der Fähigkeit, Speicherbarrieren direkt zu lesen oder zu schreiben, den eingebauten Mechanismus anstelle dieses Idioms verwenden. Das Implementieren dieses Codetyps in einem Makro ermöglicht das Ändern der Methode in der gesamten Codebasis.

EDIT: User Sharth hat einen großen Punkt, dass, wenn dieser Code in einer Umgebung ausgeführt wird, wo die Adresse des Zeigers ein physischen ist eher als virtuelle Adresse (oder eine virtuelle an eine bestimmte physikalische Adresse abgebildet Adresse), Dann könnte das Ausführen dieser Leseoperation eine Aktion an einem Peripheriegerät verursachen.

+2

Weiter könnte ein Makro es offensichtlicher machen, was vor sich geht ... (#define READ_MEMORY_BARRIER ...) – Aaron

+1

Der erste Schritt sollte sein zu bewerten, ob es tatsächlich eine Speicherbarriere schafft. Dies scheint die Absicht zu sein, aber volatile Variablen auf vielen Plattformen sind nur in Bezug auf andere volatile Variablen geordnet. Selbst wenn es für diese eingebettete Plattform funktioniert, funktioniert es möglicherweise nicht für eine andere; Ich würde nach einer besseren, portableren Lösung für die Schaffung von Barrieren suchen. –

+1

Ich denke nicht, dass es etwas mit Speicherbarrieren zu tun hat. Es ist eine eingebettete Plattform und es bildet wahrscheinlich eine Variable auf ein IO ab. –

9

Also hier ist eine lange Einstellung.

Wenn diese Adresse auf eine Speicherbereichszuordnung auf einem FPGA oder einem anderen Gerät zeigt, unternimmt das Gerät möglicherweise etwas, wenn Sie diese Adresse lesen.

+0

Warum eine Totale? Ich denke, das ist eine vollkommen logische Erklärung. +1 –

+0

Die ursprüngliche Frage fehlte eine Menge der Klarstellungen, die es klar machen, dass dies auf einem eingebetteten System usw. geschieht. –

-1

Im Allgemeinen ist das ein schlechter Code.

In C und C++ volatil bedeutet sehr wenige und bietet keine implizite Speicherbarriere. Also dieser Code ist nur ganz falsch Uness ist es geschrieben als

memory_barrier(); 
*(volatile UINT16 *)&someVar->something; 

Es ist nur schlechter Code.

Extension:volatile macht nicht variabel Atom!

Reed dieser Artikel: http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt

Aus diesem Grunde volatile sollte so gut wie nie in der richtigen Code verwendet werden.

+2

Eh !? Was bedeutet das? – Clifford