Forum: Compiler & IDEs .discards qualifiers from pointer target type


von Heiko (Gast)


Lesenswert?

Hallo!

In meinem Programm benutze ich eine Art "Empfangspuffer":
1
volatile char rxbuffer[11]={0,0,0,0,0,0,0,0,0,0,0};

Dieser wird in einer Interruptroutine verändert:
1
ISR(USART_RX_vect)
2
{
3
  if ((rxstatus&0x0F)<=10)
4
  {
5
    rxbuffer[rxstatus&0x0F]=UDR0;

Ich setze "volatile", damit der Compiler nicht auf die Idee kommt das 
irgendwie zu optimieren.

So, irgendwann möchte ich aber auch selbst mal was mit dem Puffer 
Anfangen:
1
switch(get_command(&rxbuffer[0]))

Natürlich meckert da der GCC mit einer Warnung:
1
passing argument 1 of 'get_command' discards qualifiers from pointer target type

Wie bekomme ich die Warnung nun weg?
den Puffer zuerst in ein temporäres Array kopieren und mit dem 
temporären Array weiterarbeiten? Geht das auch eleganter?

Danke, Heiko.

von Rolf Magnus (Gast)


Lesenswert?

Ja, indem du bei get_command den Paramter auf volatile char* änderst.

von Heiko (Gast)


Lesenswert?

Dann meckert der Compiler bei allen, was der Funktion nicht "volatile" 
übergeben wird oder nicht?

von Karl H. (kbuchegg)


Lesenswert?

Heiko wrote:
> Dann meckert der Compiler bei allen, was der Funktion nicht "volatile"
> übergeben wird oder nicht?

Nein. Warum sollte er?

Bei voltaile ist es nichts anders als bei const. Allerdings
ist es bei const leichter einzusehen. Daher lass mich auf
const umschalten.

void foo( const char* )

Dieser Funktionsprototyp gibt dem Aufrufer die Zusicherung,
dass sich die Funktion nicht an den Charactern (auf die der
Pointer zeigt) vergreifen wird und dass die Funktion sie
nicht ändern wird.

Das ist unmittelbare Voraussetzung dafür, dass man da einen
konstanten String übergeben kann:

   foo( "Juhu" );

Aber: das heist nicht, dass der übergebene String konstant sein
muss! Wenn die Funktion mir die Zusicherung macht, dass sie
am String nichts ändert, dann ist das doch kein Beinbruch, wenn
sie es im Prinzip könnte (weil ich ihr einen Pointer auf entsprechenden
Speicher übergebe), die Funktion es aber nicht tut

   char Text[30];

   foo( Text );

Genauso ist es mit volatile. Volatile markiert eine Variable
als 'mach keine Optimierungen damit'. Wenn nun eine Funktion
auf einem übergebenen Parameter keine Optimierungen machen
will, dann ist das doch auch in dem Fall kein Beinbruch, wenn
sie es im Prinzip machen könnte (weil das Aufrufargument
entsprechend ist). Ist aber das Aufrufargument so, dass
bereits dieses als 'nicht optimierbar' gekennzeichnet ist,
dann muss (!) sich auch die Funktion daran halten.

const und volatile habe etwas mit Einschränken zu tun. Beide
schränken die möglichen Operationen mit diesen Variablen ein.
Unterliegt das was du in eine Funktion hineinschiebst, bereits
irgendwelchen Einschränkungen, dann muss sich die Funktion auch
verpflichten, diese Einschränkungen zu respektieren. Respektiert
deine Funktion diese Einschränkungen obwohl sie es in einem
konkreten Fall nicht muesste, dann passiert nichts Schlimmes.

Ist wie im täglichen Leben: Besteht bei einer Brücke ein Limit
für 15 Tonnen, so heist das das 20 Tonner nicht drüber dürfen.
Aber mit deinem PKW, mit lediglich 1 Tonne kannst du drüber
fahren, auch wenn du die 15 Tonnen nicht erreichst.

von Heiko (Gast)


Lesenswert?

Ja, sehe ich ein, aber in der Funktion kann er doch optimieren wie er 
möchte, ich will nur nicht, dass er in der Interruptroutine optimiert 
(dann hätte ich ja irgendwann nur noch "volatile Funktionen"- ist ja 
auch nicht zweckmäßig).

Also entweder Variable vorm Übergeben :D umkopieren, oder die 
Optimierung kurzzeitig in der Interruptroutine abschalten (wie ging das 
gleich nochmal?).

Danke, Heiko.

von Karl H. (kbuchegg)


Lesenswert?

Heiko wrote:
> Ja, sehe ich ein, aber in der Funktion kann er doch optimieren wie er
> möchte,

Nein, kann er nicht.
Es ist ja nicht die Funktion die das bestimmen kann. Es ist
die Variable, die du der Funktion übergibst. Die Variable
sagt von sich selbst: Mit mir dürfen keine Optimierungen
gemacht werden.

> ich will nur nicht, dass er in der Interruptroutine optimiert
> (dann hätte ich ja irgendwann nur noch "volatile Funktionen"- ist ja
> auch nicht zweckmäßig).

Um ehrlich zu sein:
Bei Arrays kannst du dir da volatile in der Praxis sowieso sparen.
Es ist mehr als Unwahrscheinlich, dass der Compiler auf Arrays
irgendwelche bösen Optimierungen machen kann.

> Also entweder Variable vorm Übergeben :D umkopieren, oder die
> Optimierung kurzzeitig in der Interruptroutine abschalten (wie ging das
> gleich nochmal?).

Beides Mist.

Aber du kannst folgendes machen:

char rxbuffer[11]={0,0,0,0,0,0,0,0,0,0,0};

ISR( ... )
{
  volatile char* rxBufferTemp = rxBuffer;

  // und ab hier nur noch mit rxBufferTemp
  // weiterarbeiten

dann besteht der volatile Schutz nur innerhalb der ISR.
Was seinerseits aber auch wieder keinen Sinn macht, warum
soll der Compiler sich in der ISR nicht austoben dürfen.

Du solltest dir aber noch mal gut überlegen, warum man solche
Variablen überhaupt volatile macht. Es ist nämlich nicht so,
dass jede Variable, die in einer ISR vorkommt automatisch
volatile sein muss. Bei diesen volatile Variablen geht es
darum, dass sie ja nicht nur in der ISR sondern auch an
anderen Stellen im Programm benutzt werden. Und nur deswegen
benötigt man das volatile. Und da geht es hauptsächlich im
die lesenden Zugriffe auf diese Variablen und nicht so sehr
um die schreibenden. Denn nur die lesenden Zugriffe können
im Regelfall davon profitieren dass der Compiler nicht
jedesmal auf eine Variable zugreift, sondern sie in einem
Register bis zur nächsten (lesenden) Verwendungen vorhält.

von Heiko (Gast)


Lesenswert?

Ich hatte halt mal irgendwann das Problem, dass mir der Compiler etwas 
wegoptimiert hat, dass macht er scheinbar gerne, wenn man auf Register 
zugreift. Deshalb versuche ich jetzt halt bei Registerzugriffen die 
Optimierung zu verhindern.

Ich denke, dass der Compiler bei
1
rxbuffer[rxstatus&0x0F]=UDR0;

"denkt", dass da ja immer nur das Gleiche bei rauskommen kann (er weiß 
ja nicht, dass UDR0 außerhalb seiner "Sinneswahrnehmung" verändert 
werden kann) und optimiert es weg- das macht mich aber sauer.

Vielleicht wurde das Problem aber jetzt schon behoben (ist schon länger 
her) und AVR-GCC optimiert nicht mehr bei Zuweisungen in denen Register 
mitspielen?

von der mechatroniker (Gast)


Lesenswert?

In so einem Fall hat das Makro, daß das Register definiert, volatile zu 
sein. Alles andere ist doch irgendwie etwas "von hinten durch die Brust 
ins Auge" geschossen.

Beispielsweise
1
#define UDR0 *(volatile unsigned char *) 0x78

(nagel mich nicht an der 0x78 fest, hab gerade nicht ins Datenblatt 
geschaut). Sollte bei den neueren Headern der Avr-lib aber so definiert 
sein. Ansonsten halt selber ein Makro (MYUDR0 oder so) schreiben.

Eine Variable, die in einer ISR verwendet wird, als volatile zu 
deklarieren, ist normalerweise unnötig, wenn es nur darum geht, 
Optimierungen innerhalb der ISR zu unterbinden, denn diese Optimierungen 
richten ja keinen Schaden an - schließlich kann die ISR nicht 
unterbrochen werden (ein gezieltes sei(); in der ISR mal ausgenommen, 
aber wer das macht, sollte eh genau wissen, was er da tut).

von Karl H. (kbuchegg)


Lesenswert?

Heiko wrote:

> Ich denke, dass der Compiler bei
>
>
1
> rxbuffer[rxstatus&0x0F]=UDR0;
2
>
>
> "denkt", dass da ja immer nur das Gleiche bei rauskommen kann (er weiß
> ja nicht, dass UDR0 außerhalb seiner "Sinneswahrnehmung" verändert
> werden kann)

Doch das weis er.
Durch deklarieren von rxbuffer als volatile, kannst du das 'Problem'
im Übrigen auch nicht beheben. Wenn es hier ein Problem gibt, dann
kann es nur an UDR0 liegen. Und das liegt ausserhalb deines
Einflussbereiches, da UDR0 (selbstverständlich korrekt, also mit
volatile) in den AVR Headers definiert ist.

> Vielleicht wurde das Problem aber jetzt schon behoben (ist schon länger
> her) und AVR-GCC optimiert nicht mehr bei Zuweisungen in denen Register
> mitspielen?

Selbstverständlich nicht. Alle auf diese Art definierten Register
sind selbstverständlich als volatile markiert.

von Heiko (Gast)


Lesenswert?

Ich hab nochmal in den Headern nachgeschaut- da sind alle Register 
volatile definiert. Also entweder das ist neu und wurde geändert oder 
meine schlechte Erfahrung hatte doch nichts mit den Registern zu tun...

Dann nehme ich das "volatile" mal wieder weg.

Falls der mir wieder mal was wegoptimiert melde ich mich nochmal.

Danke!

MfG, Heiko.

von Rolf Magnus (Gast)


Lesenswert?

> Vielleicht wurde das Problem aber jetzt schon behoben (ist schon länger
> her) und AVR-GCC optimiert nicht mehr bei Zuweisungen in denen Register
> mitspielen?

Der gcc selbst hat von den Registern keine Ahnung. Diese sind aber in 
der avr-libc bereits als volatile definiert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Heiko wrote:

> Ich hab nochmal in den Headern nachgeschaut- da sind alle Register
> volatile definiert. Also entweder das ist neu und wurde geändert

Zumindest in den letzten reichlich 5 Jahren nicht mehr geändert, weiter
reicht das CVS-Geschichtswissen der avr-libc nicht zurück.  (Davor hat
sie Marek Michalkiewicz auf seiner privaten Platte gepflegt.)

> oder
> meine schlechte Erfahrung hatte doch nichts mit den Registern zu tun...

Sehr wahrscheinlich wohl eher dieses.

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
Noch kein Account? Hier anmelden.