warning: passing argument discards qualifiers

Gast #802953
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?
Angehängte Dateien:
Gast #802965
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?
Gast #802967
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.).
Gast #802975
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.
Angehängte Dateien:
Gast #803127
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.
#803187
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.
Gast #803193
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
Gast #803202
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...
Gast #803265
> 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.
Gast #803296
>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...
Gast #803396
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.
#803620
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
#803630
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
Gast #1441545
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
#1442204
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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.