Forum: Compiler & IDEs einfacher If-Vergleich funktioniert einfach nicht :(


von Julian W. (julian-w) Benutzerseite


Lesenswert?

Hallo,
ich bin langsam am verzweifeln...

Ich will einfach nur prüfen, ob zwei char-Werte gleich sind. Doch das 
will einfach nicht funktionieren!
1
volatile char puffer[37];
2
3
void ByteEmfpangen(char empfangen)
4
{
5
  [...]
6
7
  char tmp
8
  tmp = puffer[35];
9
  uart_write_char(tmp);
10
  if(tmp == 0xFF)
11
  {
12
       MachWas();
13
  }
14
15
  [...]
16
}

Das will einfach nicht funktionieren! Auf der UART schickt mir der 
Atmega32 ein 0xFF!? Also müsste die Bedingung doch erfüllt sein, aber er 
führt einfach den Code in der Bedingung nicht aus (er müsste dann 
nämlich eine LED anschalten, was er aber nicht tut).

Alle Fehler am Code (auser den mit der if-Bedingung), wie z.B. das die 
UART nicht richtig sendet oder das die LED nicht funktioniert/falsch 
angeschlossen ist, kann ich ausschließen. Hab das alles schon genügend 
oft ausprobiert.

Ich weiß leider keinen Rat mehr. Hoffe, ihr könnt mir weiter helfen!

MfG
Julian

von Hannes (Gast)


Lesenswert?

was machst Du mit dem (char empfangen)? Nichts, wie's scheint.

von Julian W. (julian-w) Benutzerseite


Lesenswert?

1
  [...]

Das soll bedeuten, das da noch weitere Code steht, der jetzt aber nicht 
für mein Problem relevant ist. Da wird dieser Parameter noch benötigt.

von Klaus W. (mfgkw)


Lesenswert?

Vielleicht den Vergleich mal ändern zu: tmp == (char)0xFF

von Hannes (Gast)


Lesenswert?

Vielleicht den Vergleich mal ändern zu: tmp == (char)0xFF

Schmarrn. 0xFF ist schon char.

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Vielleicht den Vergleich mal ändern zu: tmp == (char)0xFF

Das wars... Jetzt funzt es endlich! Puhh
Scheinbar stößt sich GCC daran, wenn da nicht extra (char) steht.

von Hannes (Gast)


Lesenswert?

>Auf der UART schickt mir der Atmega32 ein 0xFF!?

weil in puffer[35] ein 0xFF drinsteht.

von Sven (Gast)


Lesenswert?

Kann diesen Sachverhalt mal jemand erklären?! Wieso interpretiert der 
Compiler nicht von alleine 0xFF als char? Zumal ja tmp auch ein char 
ist. Sollte es da Komplikationen geben, so müsste doch zumindest der 
Compiler meckern, dass dort Äpfel mit Birnen verglichen wird.

von (prx) A. K. (prx)


Lesenswert?

Hannes schrieb:

> Schmarrn. 0xFF ist schon char.

Schmarrn. 0xFF ist immer vom Typ int. Alle Zahlen ohne Suffix die in 
int passen sind int. Und wenn char vorzeichenbehaftet ist (also oft), 
dann passt es auch nicht mal rein.

von Markus (Gast)


Lesenswert?

> Schmarrn. 0xFF ist schon char.

Nein, ist es nicht. char ist beim avr-gcc signed. Demnach wäre 0xff 
schon short.

von Oliver (Gast)


Lesenswert?

>Das soll bedeuten, das da noch weitere Code steht, der jetzt aber nicht
>für mein Problem relevant ist. Da wird dieser Parameter noch benötigt.

Wenn du schon genau weißt, wo der Fehler steckt, warum fragst du dann 
überhaupt noch?

>Alle Fehler am Code (auser den mit der if-Bedingung), wie z.B. das die
>UART nicht richtig sendet oder das die LED nicht funktioniert/falsch
>angeschlossen ist, kann ich ausschließen.

Na prima. Das ist mal wieder einer der Fälle, in denen ein garantiert 
fehlerfreies Programm nicht funktioniert - denn die paar Zeilen 
gezeigter Code sind ebenfalls richtig. Da bleibt, wie in 99% der auch 
sonst hier vorkommenden Fälle, als Ursache nur noch ein Compilerfehler 
oder ein bisher unerkannter Bug im Prozessor.

Geh einfach mal davon aus, das der Compiler sowas wie
1
if(tmp == 0xFF)
2
  {
absolut fehlerfrei übersetzt.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Was lernen wir daraus?

Wenn von echten Texten die Rede ist, kann man char benutzen (solange man 
sich im Bereich ASCII Code bewegt).

Wenn man aber von Bytes redet, ist char einfach der falsche Datentyp. 
Für Bytes benutzt man immer unsigned char.
Dann passieren solche Probleme nicht.

von Karl H. (kbuchegg)


Lesenswert?

Oliver schrieb:

> Geh einfach mal davon aus, das der Compiler sowas wie
>
1
if(tmp == 0xFF)
2
>   {
3
>
> absolut fehlerfrei übersetzt.

LOL.
Klar macht er das. Die Frage ist eher: Weiß der Fragesteller, was hier 
richtig ist :-)


Richtig ist:
Wir wissen, das char beim avr-gcc ein signed char ist und das avr-gcc 
2-er Komplementarithmetik benutzt.

tmp ist ein char und enthält 0xFF

die Konstante 0xFF ist wie alle Konstanten erst mal ein int (dezimal 
255). Damit stehen im Vergleich sich die beiden Datentypen

     if( char == int )

gegenüber.
Die C-Regeln verlangen, dass der kleinere der beiden Typen auf den 
Datentyp des größeren gehievt wird. In dem Fall wäre das int.
0xFF ist schon ein int, da passiert also nichts
Aber tmp. tmp ist ein char. Ein signed char. Und da in 0xFF das MSB 
gesetzt ist, ist das eine negative Zahl (nämlich -1). Wird diese auf 16 
Bit (die Länge eines int auf dem avr-gcc) erweitert, wird daraus 0xFFFF 
(ebenfalls -1, aber diesmal als int)

Und damit lautet der Vergleich, wenn wir mal die Werte einsetzen und für 
alles 16-Bit Hex Schreibweise benutzen:

   if( 0xFFFF == 0x00FF )

Tja. Und da kann man jetzt lange warten. 0xFFFF und 0x00FF werden 
niemals gleich sein.

mit unsigned char anstelle von char, so wie man es benutzt wenn man 
einfach nur mit Bytes zu tun hat, wär das nicht passiert.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Markus schrieb:
>> Schmarrn. 0xFF ist schon char.
>
> Nein, ist es nicht. char ist beim avr-gcc signed. Demnach wäre 0xff
> schon short.

Nein ist es nicht.
1
#define DEFAULT_SIGNED_CHAR 1

Guckst du
   http://gcc.gnu.org/viewvc/trunk/gcc/config/avr/avr.h?revision=147817

Asserdemm sollte gcc mit -W -Wall sagen:
>> warning: Comparison is always false due to limited range of data type

Johann

von Oliver (Gast)


Lesenswert?

Soweit die Theorie. Nur, wie passt die zur Praxis?
1
volatile char puffer[37];
2
3
int main(void)
4
{
5
6
  char tmp;
7
  tmp = puffer[35];
8
  //uart_write_char(tmp);
9
  if(tmp == 0xFF)
10
  {
11
       volatile int a = 1;
12
  }
13
14
}
1
...
2
000000ce <main>:
3
volatile char puffer[37];
4
5
int main(void)
6
{
7
  ce:  df 93         push  r29
8
  d0:  cf 93         push  r28
9
  d2:  00 d0         rcall  .+0        ; 0xd4 <main+0x6>
10
  d4:  cd b7         in  r28, 0x3d  ; 61
11
  d6:  de b7         in  r29, 0x3e  ; 62
12
13
  char tmp;
14
  tmp = puffer[35];
15
  d8:  80 91 23 01   lds  r24, 0x0123
16
  //uart_write_char(tmp);
17
  if(tmp == 0xFF)
18
  dc:  8f 3f         cpi  r24, 0xFF  ; 255
19
  de:  21 f4         brne  .+8        ; 0xe8 <main+0x1a>
20
  {
21
       volatile int a = 1;
22
  e0:  81 e0         ldi  r24, 0x01  ; 1
23
  e2:  90 e0         ldi  r25, 0x00  ; 0
24
  e4:  9a 83         std  Y+2, r25  ; 0x02
25
  e6:  89 83         std  Y+1, r24  ; 0x01
26
  }
27
28
}
29
  e8:  80 e0         ldi  r24, 0x00  ; 0
30
  ea:  90 e0         ldi  r25, 0x00  ; 0
31
  ec:  0f 90         pop  r0
32
  ee:  0f 90         pop  r0
33
  f0:  cf 91         pop  r28
34
  f2:  df 91         pop  r29
35
  f4:  08 95         ret

Oliver

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Übersetze mit
1
 -fverbose-asm -save-temps

und zeig uns den erzeugten Assembler (foo.s)

Johann

von (prx) A. K. (prx)


Lesenswert?

Diesmal war's ja auch mit -funsigned-char übersetzt worden.

von Oliver (Gast)


Lesenswert?

>Diesmal war's ja auch mit -funsigned-char übersetzt worden.

Stimmt :-)

Mit -fsigned-char (und -Os) kommt das hier raus:
1
int main(void)
2
{
3
4
  char tmp;
5
  tmp = puffer[35];
6
  ce:  80 91 23 01   lds  r24, 0x0123
7
  if(tmp == 0xFF)
8
  {
9
       volatile int a = 1;
10
  }
11
12
}
13
  d2:  80 e0         ldi  r24, 0x00  ; 0
14
  d4:  90 e0         ldi  r25, 0x00  ; 0
15
  d6:  08 95         ret

Da stimmen Theorie und Praxis dann übererein.

Oliver

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> Wenn man aber von Bytes redet, ist char einfach der falsche Datentyp.

Das mußt Du nicht mir sagen, sondern den Entwicklern des C-Standards
Die habe das mit den negativen Buchstaben verbrochen.

Und da man ja immer die heilige Kompatibilitäts-Kuh durchs C-Dorf 
treiben muß, wird das auch weiterhin Milliarden Programmierer zur 
Verzweiflung bringen.


> Für Bytes benutzt man immer unsigned char.
> Dann passieren solche Probleme nicht.

Allerdings wird man dann jedesmal vom AVR-GCC doof angemotzt, sobald man 
ne String-Funktion aufruft (aus der string.h, stdio.h, ...).
Da hilft dann nur, alle Stringfunktionen zu casten.
Oder sich ne "ustring.h" schreiben.


Peter

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


Lesenswert?

Peter Dannegger schrieb:

>> Für Bytes benutzt man immer unsigned char.
>> Dann passieren solche Probleme nicht.
>
> Allerdings wird man dann jedesmal vom AVR-GCC doof angemotzt, sobald man
> ne String-Funktion aufruft

Ist ja auch OK.  Eine Stringfunktion benutzt keine Bytes, sondern chars
(darstellbare Zeichen).

In aller Regel gibt es bei den EA-Operationen genau einmal einen
Übergang zwischen char und uint8_t, beim Übergang zwischen der
internen Zeichendarstellung (char) und dem Hardwareregister (uint8_t).
Dort braucht man dann einen typecast.  Alles andere kann typenrein
arbeiten.

Bei C++ ist der Compiler noch pingeliger und besteht darauf, dass
man char, signed char und unsigned char als drei voneinander
verschiedene Datentypen behandelt.  Bei C ist ein Programm, das
dies nicht tut, ,,nur'' nicht mehr ``strictly conforming'', d. h.
sein Verhalten hängt von Dingen ab, die ``implementation-defined''
sind.

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:

> Das mußt Du nicht mir sagen, sondern den Entwicklern des C-Standards
> Die habe das mit den negativen Buchstaben verbrochen.

Ob "char" mit oder ohne Vorzeichen arbeitet, das ist ist im C-Standard 
keineswegs definiert.

Das haben letztlich die Leute von DEC verbrochen, die der PDP-11 eine 
automatische Vorzeichenerweiterung bei Byteverarbeitung verpasst haben. 
Und diese PDP-11 war über eine recht lange Zeit die Standardplattform 
für Unix und somit für C.

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.