2016-06-22 14 views
9

Sagen, ich habe eine StrukturZeiger in einem volatilen struct in C

typedef struct A{ 

int a1; 
int *a2; 

}A_t; 

Nun, wenn ich eine Instanz dieser Struktur erklären volatil zu sein -

volatile A_t trial; 

Und ich verwenden, um einen flüchtigen Zeiger auf Zugang diese flüchtige Struktur.

volatile A_t *ptrToTrial = &trial; 

Wenn ich versuche, dies zu tun:

int *ptrToField = ptrToTrial->a2; 

Sollte ptrToField auch flüchtig sein? Wüsste der Compiler, dass prtToField ohne explizite Erwähnung flüchtig ist, weil auf ihn über ptrToTrial zugegriffen wird, der flüchtig ist?

Auch wenn es eine Funktion ist -

function trialFunction(A_t *trialptr) 
{ 
    int *p = trialptr->a2; 

} 

Wenn wir diese Funktion mit dem flüchtigen ptr nennen oben erklärt -

trailFunction(ptrToTrial) 

Ich erhalte eine Fehlermeldung: volatile A_t* is incompatible with parameter of type A_t.

Also, wenn ich die Funktionsdefinition ändern, um volatile einzuschließen, sehe ich keinen Fehler.

function trialFunction(volatile A_t *trialptr) 
{ 
    int *p = trialptr->a2; 

} 

Sollte nicht der Compiler beschweren sich auch über den Zeiger p - weil p nicht flüchtig ist und trialptr->a2 ist flüchtig?

+1

Ihr Code macht nicht klar, wie Sie 'volatile' verwenden. Aber sei dir bewusst, dass es nicht das tut, was viele denken. Tatsächlich [ist es in Wirklichkeit praktisch nutzlos] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html). –

+2

Nur Dinge, die im Typspezifizierer explizit als 'flüchtig' deklariert werden, sind flüchtig. In diesem Fall sind 'trial' und' * ptrToTrial' volatil. 'ptrToTrial-> a2' ist flüchtig, da es ein Mitglied einer flüchtigen Struktur ist. Jedoch sind 'ptrToTrial-> a2 [0]' und 'ptrToField [0]' (sofern diese gültig sind) nicht flüchtig. –

+0

"Und ich verwende einen flüchtigen Zeiger, um auf diese flüchtige Struktur zuzugreifen." 'volatile A_t * ptrToTrial = &trial;' -> Nein, 'ptrToTrial' ist nicht 'volatile', was darauf hinweist, ist' volatile'. – chux

Antwort

1

Bitte beachten Sie, dass int *a2; in Ihrem struct A nicht flüchtig ist. So

int *ptrToField = ptrToTrial->a2; 

ptrToField ist nicht volatile.

trailFunction(ptrToTrial) erhält Fehler, da die Funktion trailFunctionA_t *trialptr erwartet, aber sie passieren volatile A_t*, es ist offensichtlich Fehler kompilieren.

Und schließlich:

function trialFunction(volatile A_t *trialptr) 
{ 
    int *p = trialptr->a2; 
} 

Es ist OK, um zu kompilieren, weil a2 ‚s Typ int* ist.

-1

Meine bevorzugte Platzierung ist normalerweise in der Zeigerdeklaration. Auf diese Weise werden alle Register in der Struktur vom Compiler als flüchtig behandelt, und dennoch ist es möglich, andere (z. B. RAM-basierte Schatten) Instanzen der Struktur zu haben, die nicht flüchtig sind, weil sie nicht tatsächlich Hardware-Register sind unterhalb.

ich Ihnen daher raten zu verwenden: einen schönen Tag

typedef volatile struct 

Haben

+0

"_Have a nice day_"? Sitzen Sie in einem Café? –

+0

Ja;) http://images.fineartamerica.com/images-medium-large-5/have-a-nice-day-cafe-brian-wallace.jpg – AkrogAmes

3

Should ptrToField be volatile as well?

Mit Ihrer Definition von struct A wies die Sache vom Mitglied a2 nicht erklärt wird volatile zu sein. Dass eine bestimmte Instanz von struct A ist volatile impliziert, dass sein Mitglied a2 (der Zeiger) ist volatile, aber nicht, dass die Sache, die es zu den Punkten ist volatile. Dies ist der Unterschied zwischen int * volatile (entspricht dem tatsächlichen Fall) und .

Die Initialisierung Sie beschreiben ...

int *ptrToField = ptrToTrial->a2; 

... initialisiert ptrToField mit dem Wert von ZeigerptrToTrial->a2. Weil ptrToTrial auf ein volatile Objekt zeigt, muss das Programm den Zeiger (ein Mitglied dieses flüchtigen Objekts) aus dem Hauptspeicher laden. Da das Ding, auf das gezeigt wird, nicht (volatil) ist, sind jedoch keine Informationen verloren und es besteht kein (neues) Risiko darin, den Typ des ptrToField Ziels als ein einfaches int zu deklarieren. Sicherlich hat es keinen Vorteil, ptrToField selbst als volatil zu deklarieren.

Beachten Sie auch, falls es unklar ist, dass der Name Ihrer Variablen ptrToField nicht mit der Verwendung übereinstimmt, zu der Sie es setzen. Sie initialisieren es nicht, um auf ein Mitglied Ihrer struct zu zeigen; Stattdessen initialisieren Sie es als Kopie eines Mitglieds Ihrer struct.

Would the compiler know that prtToField is volatile without explicit mention because it is accessed through ptrToTrial which is volatile?

Es ist kein solches Wissen auszuüben erforderlich es haben könnte, und dieses Wissen in jedem Fall wäre wahrscheinlich in ihrem Umfang sehr begrenzt. Es weiß, wie diese Variable initialisiert wurde, aber es kann schwierig sein vorherzusagen, wann und wie der Wert danach geändert werden könnte. In jedem Fall sind Informationen, die nicht vom deklarierten Typ der Variablen übermittelt werden, für die Standard-C-Semantik Ihres Programms nicht relevant. Kein

Shouldn't the compiler also complain about the pointer p - because p is non-volatile and trialptr->a2 is volatile?

, denn obwohl trialptr->a2 flüchtig ist, gibt es kein Problem mit dem Lesen seiner Wert (bei einem gegebenen Zeitpunkt) und diesen Wert auf eine andere Variable zuweisen. Objektwerte sind Bitmuster, sie sind weder flüchtig noch nichtflüchtig - das ist eine Eigenschaft ihres Speichers, wie sie über die L-Werte, auf die sie zugreifen, kommuniziert wird.

+0

Macht Sinn. Vielen Dank. – Curious91

+0

Wäre es also nicht immer sinnvoll, einen flüchtigen Zeiger auf diese Weise definiert zu haben - A_t volatile * ptrToTrial = &trial; statt flüchtiger A_t * ptrToTrial = & trial? – Curious91

+1

@ Curious91, 'volatile int *' und 'int volatile *' werden unterschiedlich geschrieben, aber sie sind äquivalent, genauso wie 'volatile int' und' int volatile' äquivalent sind. Dies ist das gleiche wie für den Typqualifikator "const", was ein häufigerer Kontext für Probleme wie diese ist. –