Hallo, ich habe eine Variable, die ich mit utoa in einen String wandle
und per USART senden möchte. Klappt auch wunderbar.
Jetzt habe ich den Umwandlungsbefehl von der UART-Senderoutine in die
Main-Routine verschoben (siehe Anhang) und bekomme folgende Warnings:
../sensors_new.c:240: warning: passing argument 1 of 'uart_puts'
discards qualifiers from pointer target type
../sensors_new.c: In function 'main':
../sensors_new.c:318: warning: passing argument 2 of 'utoa' discards
qualifiers from pointer target type
Kompiliere ich ein zweites Mal, sind die Warnings weg. Verändere ich
etwas am Programm, sind sie beim ersten Kompilieren da, dann wieder weg.
Ist das etwas, worüber ich mir Sorgen machen muss?
Die Variable "conversion_buffer" war vorher als "char" deklariert. Bei
der Änderung habe ich diese dann als globale Variable "volatile char"
deklariert (siehe Anhang im ersten Post). Wenn ich sie nicht als
"volatile" deklariere, sind die warnings weg, allerdings muss ich sie
doch als "volatile" deklarieren, da zwei Routinen auf die Variable
zugreifen müssen, oder?
Dass die Warnungen beim zweiten Kompilieren weg sind, leuchtet ein.
Dafür sorgt nämlich dein Makefile. Das passt auf, dass auch nur dann neu
kompiliert wird, wenn sich was an der Datei geändert hat (Zeitpunkt der
letzten Änderung).
Unter "qualifiers" versteht man diese Dingers vor den Variablen
("const", "volatile", "static" usw.).
Nachtrag: Zum Thema "volatile" oder nicht: Das ist gedacht, um den
Optimierer zu knebeln, insofern hast du mit deiner Annahme Recht. Les
dazu auch mal die Doku vom Linux-Kernel, da ist ein Essay dabei
(Anhang).
Um das Problem zu umgehen, musst du casten:
Danke für Deine Antwort. Bin heute schon zu müde, um den Text im Anhang
zu lesen, das mache ich dann morgen. Hab das mit dem casten gerade noch
schnell probiert, jetzt kommen dafür andere Warnings:
../sensors_new.c:239: warning: passing argument 1 of 'uart_puts' makes
pointer from integer without a cast
../sensors_new.c: In function 'main':
../sensors_new.c:317: warning: passing argument 2 of 'utoa' makes
pointer from integer without a cast
Komisch, dabei habe ich die Casts doch extra eingefügt...Werde morgen
mal versuchen da weiter durchzusteigen.
die casts müssen natürlich auf "char *" gehen, du willst ja nur den
"volatile" qualifier wegkriegen...
also
1
utoa(dt,(char*)conversion_buffer,10);
Ich würd allerdings eher das "volatile" bei der Variablendeklaration
weglassen, wenn du das an "utoa" übergibst ist das eh sinnlos, ausser du
sperrst vor dem utoa Aufruf explizit alle interrupts.
Ja, jetzt sind die Warnings weg. Leider habe ich gar keine Ahnung, was
ich da gemacht hab. In C von A bis Z hab ich zu Casting nur gefunden,
dass es sich um Typumwandlungen handelt. Hat einer von Euch eine gute
Quelle, in der das beschrieben steht? Ansonsten werd ich morgen mal
bischen im Internet suchen, da findet sich bestimmt einiges zu der
Thematik.
Den Text im Anhang habe ich etwas angelesen, da geht es um volatile,
aber nicht um casts. So wirklich habe ich das allerdings leider auch
nicht verstanden.
Gute Nacht!
Dennis
Volatile hat übrigens nicht viel mit "global" zu tun. Und für Arrays ist
Volatile in der Regel nicht nötig, ich glaube Arrays landen immer im RAM
und nicht in Registern (Vielleicht weiss es jemand besser, den "Wissen"
ist bekanntlich besser als "Glauben")
In Deinem Fall ist das Volatile eh unnötig. Solange sich
Interrupt-Routinen und übrige Programteile nicht die selben globalen
Variabeln teilen, erkennt der Compiler zuverlässig, wie weit er
optimieren darf...
> Volatile hat übrigens nicht viel mit "global" zu tun. Und für Arrays> ist Volatile in der Regel nicht nötig, ich glaube Arrays landen immer> im RAM und nicht in Registern (Vielleicht weiss es jemand besser,> den "Wissen" ist bekanntlich besser als "Glauben")
Am besten ist, das volatile einfach trotzdem zu verwenden, denn schaden
tut's nicht. Dann braucht man es gar nicht zu wissen, und es besteht
nicht die Gefahr, daß eine neue Compilerversion es doch mal anders
handhaben könnte.
>Am besten ist, das volatile einfach trotzdem zu verwenden, denn schaden>tut's nicht.
Präziser: Wenn Geschwindigkeit und Codegrösse egal sind, dann schadet es
nicht...
Es ging mir natürlich um den Fall, wenn man will, daß Zugriffe auf das
Array nicht wegoptimiert werden. Da schadet volatile nicht, denn es ist
genau dazu da.
Dennis wrote:
> Die Variable "conversion_buffer" war vorher als "char" deklariert. Bei> der Änderung habe ich diese dann als globale Variable "volatile char"> deklariert (siehe Anhang im ersten Post). Wenn ich sie nicht als> "volatile" deklariere, sind die warnings weg, allerdings muss ich sie> doch als "volatile" deklarieren, da zwei Routinen auf die Variable> zugreifen müssen, oder?
Als volatile erklärt man nur dann Variablen, wenn diese sog.
Seiteneffekte haben können, die der Compiler nicht selber ermitteln
kann. Beipiel: Du greifst mittels Polling auf eine Variable zu (=warten
auf Änderung, nur lesend), die ggf. in einer Interrupt-Routine dann
wirklich verändert wird (schreibend). Der Compiler hat von dieser
Änderung im Hintergrund (IRQ) keine Ahnung und würde die Warteschleife
schlimmstenfalls wegoptimieren. Hier sagt ihm das volatile für eben
diese Variable, daß er sie doch ständig so testen muß, wie es der Code
vorgibt.
Wenn zwei Routinen auf eine Variable ändernd zugreifen, und sie das brav
sequentiell tun, ist kein Grund für volatile gegeben. Die
Schreiboperation ist beim Beenden der Routine immer vollzogen und eine
nachfolgende Routine verwendet den neuen Wert wenn sie aufgerufen wird.
Tut eine Routine das im Interrupt und eine im normalen Kontext, nützt
einem volatile auch nichts, da braucht man dann andere Mechanismen um
atomare Operationen sicherzustellen.
Bei Nebenläufigkeit muß man sich einige Gedanken mehr machen. Meistens
wendet man dabei aber volatile falsch an, bzw. es ist keine Lösung,
sondern nur eine Hoffnung.
Jürgen
Peter wrote:
> Volatile hat übrigens nicht viel mit "global" zu tun. Und für Arrays> ist Volatile in der Regel nicht nötig, ich glaube Arrays landen immer> im RAM und nicht in Registern (Vielleicht weiss es jemand besser,> den "Wissen" ist bekanntlich besser als "Glauben")
Das eine hat mit dem anderen nichts zu tun. Sicher versucht der Compiler
zu optimieren, indem er Dinge so lange wie möglich in Registern hält.
Darüberhinaus geht es aber noch um echte Code-Optimierung (oder besser
"Weg-Optimierung):
int bla;
void warte(void)
{
bla = 0;
[...]
/* tue etwas, aber rühre bla nicht mehr an */
[...]
if (bla != 0)
/* tue dies */
else
/* tue jenes */
}
Der komplette Teil von "tue dies" kann vom Compiler verworfen werden,
weil er ermitteln kann, daß sich in diesem Kontext "bla" nicht
verändert.
Würde also eine Interrupt-Routine "bla" verändern, bekäme diese Funktion
hier das gar nicht mit.
"volatile int bla;" würde dem Compiler genau diesen Seiteneffekt aber
mitteilen und der if-Test würde erhalten bleiben und auch "tue dies"
hätte eine Chance jemals ausgeführt zu werden.
Jürgen
Hallo Zsammen,
ich will das Thema nochmal aufgreifen, weil ich vor dem gleichen Problem
stehe.
Ich habe versucht, wie oben beschrieben, meine Übergabe zu Casten.
if (strncmp ((char *) &gpsmsgbuf[3], "RMC", 3) == 0).
Der Compiler meckert nun auch nicht mehr, aber das Programm hängt sich
auf sobald ich (anscheinend) öfter bzw an bestimmten Stellen lesend
drauf zugreife.
Ich habe auch schon probiert das "volatile" zu entfernen.
Das klappt so auch ganz gut, ABER ich habe irgendwie die Befürchtung,
dass das irgendwann doch Probleme gibt weil ich ja mit der UART-ISR
darauf zugreife.
Wie gesagt, so klappts bisher (2 Versuche) aber ich frage mich warum der
Compiler mein Array dann nicht wegoptimiert.
Ich schreibe an keiner anderen Stelle in das Array.
MfG,
Marten83
Hi Marten83,
wieso sollte der Compiler Dein Array wegoptimieren? Er weiß doch nicht,
was die strncmp(), die genau dieses Arrary benutzt, damit macht (weil
Kontext-Wechsel). Also muss das Array und der Zugriff darauf erhalten
bleiben und wird immer dann ausgeführt, wenn es Dein C-Quelltext
vorsieht.
jbe