Forum: Compiler & IDEs warning: passing argument discards qualifiers


von Dennis (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Dennis (Gast)


Lesenswert?

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?

von Sven P. (Gast)


Lesenswert?

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.).

von Sven P. (Gast)


Angehängte Dateien:

Lesenswert?

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:
1
volatile char conversion_buffer[7];
2
3
void send_check(void) {  
4
   ...        
5
   uart_puts((char) conversion_buffer);
6
   ...
7
}
8
9
int main(void)
10
{  
11
   ...
12
   while(1)
13
   {
14
      if (dt_change == 1);
15
      {
16
         utoa(dt,(char) conversion_buffer,10);
17
         dt_change = 0;
18
      }
19
   
20
   send_check();
21
   }
22
}

Beachte die "(char)"-Casts.

von Dennis (Gast)


Lesenswert?

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.

von Εrnst B. (ernst)


Lesenswert?

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.

von Dennis (Gast)


Lesenswert?

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

von Peter (Gast)


Lesenswert?

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...

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Peter (Gast)


Lesenswert?

>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...

von Rolf Magnus (Gast)


Lesenswert?

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.

von Juergen B. (jbeisert)


Lesenswert?

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

von Juergen B. (jbeisert)


Lesenswert?

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

von Dennis (Gast)


Lesenswert?

Danke für die ausführliche und verständliche Erklärung!

von Marten83 (Gast)


Lesenswert?

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

von Juergen B. (jbeisert)


Lesenswert?

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

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.