Forum: PC-Programmierung 2 Warnungen, wo kommen die her?


von Zitroneneis (Gast)


Lesenswert?

Hallo Profis!

Ich hab hier 2 Warnungen die ich nicht verstehe, kann mir mal jemand 
einen Tipp geben?

Problem 1:
1
//aufs strikte Minimum reduziert
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <inttypes.h>
5
#define NB_LAUFWERKE_MAX 16
6
7
typedef char Laufwerksname_t[2];
8
Laufwerksname_t ListeLaufwerke[NB_LAUFWERKE_MAX];
9
10
void print(Laufwerksname_t const * const Liste) //WARNUNG FÜR DIESE ZEILE
11
//                         ^^^^^
12
{
13
  printf("%s",Liste[0]);
14
}
15
16
int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
17
{
18
  ListeLaufwerke[0][0]='C';
19
  ListeLaufwerke[0][1]='\0';
20
  print(ListeLaufwerke);
21
  return 0;
22
}
GCC meckert
1
warning: passing arg 1 of `print' from incompatible pointer type
.
Wenn ich den ersten const (oben markiert) entfernt passt alles.
Warum? Das Argument Liste ist ein Array bzw. ein konstanter Pointer auf 
einige Einträge. Jeder dieser Einträge ist ein String, also ein 
Char-Array und somit ein weiterer Pointer. Der Inhalt vom Char-Array ist 
nicht konstant, der Pointer auf das Array schon, also 2 mal const. Wo 
ist mein Denkfehler?

Problem 2:
1
//aufs strikte Minimum reduziert
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <inttypes.h>
5
6
uint32_t NbDateien=0; //jaja ich weiß, globale Variablen sind ganz böse... ;-)
7
8
#define irgendwas 0
9
10
int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
11
{
12
  uint8_t PosAuswahl;
13
  uint8_t OffsetAnzeige;
14
  uint8_t flag_rootDir;
15
  if (irgendwas)
16
  {
17
    //tu was
18
  }
19
  else if(PosAuswahl+OffsetAnzeige>=2 && !flag_rootDir)
20
  {
21
      if(PosAuswahl+OffsetAnzeige-2<NbDateien) //WARNUNG FÜR DIESE ZEILE
22
      {
23
        //tu was anderes
24
      }
25
      //...
26
  }
27
28
  return 0;
29
}
Diesmal beschwert sich der GCC
1
warning: comparison between signed and unsigned
. Google liefert Codefetzen welche signed-Variablen enthalten, das ist 
bei mir nicht der Fall. PosAuswahl+OffsetAnzeige-2 ist bei mir doch 
immer >=0 weil die if-Abfrage nur ausgeführt wird wenn die übergeordnete 
wahr ist und diese Übergeordnete testet ja ob 
PosAuswahl+OffsetAnzeige>=2. Was ist da los?

GCC wird mit -Wall und -Wextra aufgerufen, Version 3.4.5 unter Windows.

von Lord Z. (lordziu)


Lesenswert?

0 + 0 - 2 ist aber negativ.

Und der Compiler prüft nicht, ob du semantisch in die erste if-Abfrage 
gehst. Für den Compiler kann da -2 rauskommen. Und das meckert er - 
zurecht - an.

von Kai S. (zigzeg)


Lesenswert?

Lord Ziu schrieb:
> 0 + 0 - 2 ist aber negativ.
>
> Und der Compiler prüft nicht, ob du semantisch in die erste if-Abfrage
> gehst. Für den Compiler kann da -2 rauskommen. Und das meckert er -
> zurecht - an.

Du hast Recht das der Compiler die erste if-Abfrage nicht semantisch 
analysiert. Allerdings werden auch keine Wertebereich betrachtet. So ist 
das Ergebnis einer Differenz-Operation durchaus unsigned, wenn beide 
Operanden unsigned sind.

Das Problem ist, das '2' eine Konstante vom Typ 'int' ist. Der Ausdruck 
"PosAuswahl + OffsetAnzeige" hat den Typ uint8_t. Der Compiler fuegt 
einen impliziten Cast auf 'int' ein, denn er kann immer nur gleiche 
Typen verknuepfen. Dafuer gibt es komplexe Regeln, im Prinzip wird aber 
immer auf den allgemeineren bzw. breiteren Typ gecastet - hier also 
'int'.

Wenn Du statt '2' eine unsigned Konstante verwendest, also '2U' sollte 
die Warning weg sein !

von Vlad T. (vlad_tepesch)


Lesenswert?

Was spricht eigentlich gegen folgendes:
1
//aufs strikte Minimum reduziert
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <inttypes.h>
5
#define NB_LAUFWERKE_MAX 16
6
7
typedef char Laufwerksbuchstabe_t;
8
Laufwerksbuchstabe_t ListeLaufwerke[NB_LAUFWERKE_MAX];
9
10
void print(Laufwerksbuchstabe_t const * const Liste) //WARNUNG FÜR DIESE ZEILE
11
//                         ^^^^^
12
{
13
  printf("%c",Liste[0]);
14
}
15
16
int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
17
{
18
  ListeLaufwerke[0]='C';
19
  print(&ListeLaufwerke);
20
  return 0;
21
}
Strings der Länge 2 sind ziemlich witzlos, zumindest, wenn die Länge 
statisch ist.

Anponsten ist der Fehler warhsceinlich, dass du schreiben müsstest.
print(&ListeLaufwerke);

von Vlad T. (vlad_tepesch)


Lesenswert?

nebenbei:
üblich ist:
Typen mit großem Anfangsbuchstaben,
instanzen kleiner Anfangsbuchstaben

von Zitroneneis (Gast)


Lesenswert?

Kai S. schrieb:
> Wenn Du statt '2' eine unsigned Konstante verwendest, also '2U' sollte
> die Warning weg sein !
Stimmt!

> Das Problem ist, das '2' eine Konstante vom Typ 'int' ist. Der Ausdruck
> "PosAuswahl + OffsetAnzeige" hat den Typ uint8_t. Der Compiler fuegt
> einen impliziten Cast auf 'int' ein, denn er kann immer nur gleiche
> Typen verknuepfen. Dafuer gibt es komplexe Regeln, im Prinzip wird aber
> immer auf den allgemeineren bzw. breiteren Typ gecastet - hier also
> 'int'.
Okay... '2' ist also vom Typ signed int, d.h. der Compiler castet den 
linken Teil vom Ausdruck auf signed int und meckert dann weil der rechte 
Teil unsigned ist, richtig?

Ich hab das mal ausprobiert:
1
uint32_t NbDateien=10;
2
int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
3
{
4
  uint8_t PosAuswahl=4;
5
  uint8_t OffsetAnzeige=0;
6
  if(PosAuswahl+OffsetAnzeige-2<NbDateien)
7
    printf("Ja\n");
8
  else
9
    printf("Nein\n");
10
  return 0;
11
}
funktioniert nur richtig wenn der linke Teil positiv ist. Wenn ich "2U" 
schreibe entfällt zwar die Warnung aber es geht trotzdem nicht, erst 
wenn ich NbDateien auf signed caste passt alles. Interessanterweise 
reicht ein (signed) ohne Angabe eines Datentypes. Die Warnung ist also 
(wie fast alle anderen) sehr ernst zu nehmen.
Solange mindestens einer der beiden Ausdrücke unsigned ist betrachtet 
der Compiler das MSB als "normales Bit" und nicht als Vorzeichen, was im 
oberen Fall natürlich Chaos ergibt. Nur wenn keiner der Ausdrücke 
erwiesenermaßen negativ werden kann darf man die Warnung durch ein 'U' 
unterdrücken (ohne Cast). Sehe ich das richtig?

Puh, ich glaube ich werde diese Sprache nie richtig verstehen. :-( (Und 
bevor Karl-Heinz ankommt, den K&R habe ich schon, hat auch schon oft 
geholfen. ;-) )

Vlad Tepesch schrieb:
> Was spricht eigentlich gegen folgendes:
> [...]
> Strings der Länge 2 sind ziemlich witzlos, zumindest, wenn die Länge
> statisch ist.
Compiler haben eh sehr wenig Humor (kleiner Scherz am Rande). Mal 
ernsthaft: Ich habe noch einige weitere Listen welche alle aus Strings 
(Länge>>2) bestehen und will konsistent bleiben (überall Strings).

> Anponsten ist der Fehler warhsceinlich, dass du schreiben müsstest.
> print(&ListeLaufwerke);
Huh? ListeLaufwerke ist (in diesem Kontext) doch bereits ein Pointer auf 
das erste Array-Element oder? Ich habs gerade ausprobiert, bei 
"&ListeLaufwerke" meckert der Compiler immer, egal ob 0,1 oder 2 const. 
Funktionieren tuts trotzdem. -->Hä?!?

Vlad Tepesch schrieb:
> nebenbei:
> üblich ist:
> Typen mit großem Anfangsbuchstaben,
> instanzen kleiner Anfangsbuchstaben
Du meinst
1
typedef char Typ_t[42];
2
Typ_t instanz;
? Danke für den Hinweis, das mit den Bezeichnern ist bei mir eh so eine 
Sache. Meistens nutze ich einen gräßlichen Deutsch-Englisch-Mix. 
Deutsche Wörter mit Kleinbuchstaben am Anfang kann ich irgendwie nicht 
leiden.

Danke euch erstmal, für heute hab ich genug.

von ... (Gast)


Lesenswert?

Zitroneneis schrieb:
> Solange mindestens einer der beiden Ausdrücke unsigned ist betrachtet
> der Compiler das MSB als "normales Bit" und nicht als Vorzeichen,

Nein, so einfach ist es nicht. Es wird (verfeinfacht gesagt) auf den 
'größeren' der beiden Typen gecastet und der kann durchaus 
vorzeichenbehaftet sein.

Eine andere Lösung für Dich könnte folgendes sein:
1
if(PosAuswahl + OffsetAnzeige < NbDateien + 2)
2
...

von Zitroneneis (Gast)


Lesenswert?

So, da bin ich wieder.

... schrieb:
> Zitroneneis schrieb:
>> Solange mindestens einer der beiden Ausdrücke unsigned ist betrachtet
>> der Compiler das MSB als "normales Bit" und nicht als Vorzeichen,
>
> Nein, so einfach ist es nicht. Es wird (verfeinfacht gesagt) auf den
> 'größeren' der beiden Typen gecastet und der kann durchaus
> vorzeichenbehaftet sein.
OK, hab noch mal im K&R nachgelesen und hoffe es jetzt verstanden zu 
haben, ansonsten melde ich mich wieder. Diese 
integer-promotion-Geschichten sind ganz schön kompliziert. :-(

> Eine andere Lösung für Dich könnte folgendes sein:
>
1
> if(PosAuswahl + OffsetAnzeige < NbDateien + 2)
2
> ...
3
>
Stimmt... Im Kontext kann ... -2U < ... aber deutlicher bzw. 
offensichtlicher sein, dann nutze ich lieber diese Möglichkeit.

Was ich aber nicht verstehe ist das hier:
> Vlad Tepesch schrieb:
>> Anponsten ist der Fehler warhsceinlich, dass du schreiben müsstest.
>> print(&ListeLaufwerke);
> Huh? ListeLaufwerke ist (in diesem Kontext) doch bereits ein Pointer auf
> das erste Array-Element oder? Ich habs gerade ausprobiert, bei
> "&ListeLaufwerke" meckert der Compiler immer, egal ob 0,1 oder 2 const.
> Funktionieren tuts trotzdem. -->Hä?!?
Warum funktioniert das auch wenn man die Adresse von ListeLaufwerke 
(das ist ein schon Pointer) übergibt?


Hat jemand eine Idee was es mit der ersten Warnung auf sich hat?
Zitroneneis schrieb:
> Problem 1:
>
1
> //aufs strikte Minimum reduziert
2
> #include <stdio.h>
3
> #include <stdlib.h>
4
> #include <inttypes.h>
5
> #define NB_LAUFWERKE_MAX 16
6
> 
7
> typedef char Laufwerksname_t[2];
8
> Laufwerksname_t ListeLaufwerke[NB_LAUFWERKE_MAX];
9
> 
10
> void print(Laufwerksname_t const * const Liste) //WARNUNG FÜR DIESE
11
> ZEILE
12
> //                         ^^^^^
13
> {
14
>   printf("%s",Liste[0]);
15
> }
16
> 
17
> int main(int argc __attribute__((unused)), char* argv[]
18
> __attribute__((unused)))
19
> {
20
>   ListeLaufwerke[0][0]='C';
21
>   ListeLaufwerke[0][1]='\0';
22
>   print(ListeLaufwerke);
23
>   return 0;
24
> }
25
>
> GCC meckert
>
1
warning: passing arg 1 of `print' from incompatible pointer
2
> type
.
> Wenn ich den ersten const (oben markiert) entfernt passt alles.
> Warum? Das Argument Liste ist ein Array bzw. ein konstanter Pointer auf
> einige Einträge. Jeder dieser Einträge ist ein String, also ein
> Char-Array und somit ein weiterer Pointer. Der Inhalt vom Char-Array ist
> nicht konstant, der Pointer auf das Array schon, also 2 mal const. Wo
> ist mein Denkfehler?

von Zitroneneis (Gast)


Lesenswert?

Hat keiner der Profis 10 Minuten Zeit um sich den Thread mal kurz 
anzugucken?

von Schlauch (Gast)


Lesenswert?

Ich kann den Code oben auch mit -Wall ohne Warnungen oder Fehler 
kompilieren (gcc 4.3.3).

von Zitroneneis (Gast)


Lesenswert?

Schlauch schrieb:
> Ich kann den Code oben auch mit -Wall ohne Warnungen oder Fehler
> kompilieren (gcc 4.3.3).
Du meinst Problem 1 (const * const Liste)?

von Schlauch (Gast)


Lesenswert?

Ja, Nummer 1, Laufwerkdingens.

von Zitroneneis (Gast)


Lesenswert?

"Laufwerkdingens" ist gut. :-) Ich guck mir das morgen noch mal an, 
jetzt bin ich zu müde (und mache zu viele Fehler).

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.