mikrocontroller.net

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


Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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!
volatile char puffer[37];

void ByteEmfpangen(char empfangen)
{
  [...]

  char tmp
  tmp = puffer[35];
  uart_write_char(tmp);
  if(tmp == 0xFF)
  {
       MachWas();
  }

  [...]
}

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

Autor: Hannes (Gast)
Datum:

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

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Wachtler (mfgkw)
Datum:

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

Autor: Hannes (Gast)
Datum:

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

Schmarrn. 0xFF ist schon char.

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hannes (Gast)
Datum:

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

weil in puffer[35] ein 0xFF drinsteht.

Autor: Sven (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Schmarrn. 0xFF ist schon char.

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

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
if(tmp == 0xFF)
  {
absolut fehlerfrei übersetzt.

Oliver

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:

> Geh einfach mal davon aus, das der Compiler sowas wie
>
if(tmp == 0xFF)
>   {
> 
> 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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.
#define DEFAULT_SIGNED_CHAR 1

Guckst du
   http://gcc.gnu.org/viewvc/trunk/gcc/config/avr/avr...

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

Johann

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Soweit die Theorie. Nur, wie passt die zur Praxis?
volatile char puffer[37];

int main(void)
{

  char tmp;
  tmp = puffer[35];
  //uart_write_char(tmp);
  if(tmp == 0xFF)
  {
       volatile int a = 1;
  }

}

...
000000ce <main>:
volatile char puffer[37];

int main(void)
{
  ce:  df 93         push  r29
  d0:  cf 93         push  r28
  d2:  00 d0         rcall  .+0        ; 0xd4 <main+0x6>
  d4:  cd b7         in  r28, 0x3d  ; 61
  d6:  de b7         in  r29, 0x3e  ; 62

  char tmp;
  tmp = puffer[35];
  d8:  80 91 23 01   lds  r24, 0x0123
  //uart_write_char(tmp);
  if(tmp == 0xFF)
  dc:  8f 3f         cpi  r24, 0xFF  ; 255
  de:  21 f4         brne  .+8        ; 0xe8 <main+0x1a>
  {
       volatile int a = 1;
  e0:  81 e0         ldi  r24, 0x01  ; 1
  e2:  90 e0         ldi  r25, 0x00  ; 0
  e4:  9a 83         std  Y+2, r25  ; 0x02
  e6:  89 83         std  Y+1, r24  ; 0x01
  }

}
  e8:  80 e0         ldi  r24, 0x00  ; 0
  ea:  90 e0         ldi  r25, 0x00  ; 0
  ec:  0f 90         pop  r0
  ee:  0f 90         pop  r0
  f0:  cf 91         pop  r28
  f2:  df 91         pop  r29
  f4:  08 95         ret

Oliver

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übersetze mit
 -fverbose-asm -save-temps

und zeig uns den erzeugten Assembler (foo.s)

Johann

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Diesmal war's ja auch mit -funsigned-char übersetzt worden.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Diesmal war's ja auch mit -funsigned-char übersetzt worden.

Stimmt :-)

Mit -fsigned-char (und -Os) kommt das hier raus:
int main(void)
{

  char tmp;
  tmp = puffer[35];
  ce:  80 91 23 01   lds  r24, 0x0123
  if(tmp == 0xFF)
  {
       volatile int a = 1;
  }

}
  d2:  80 e0         ldi  r24, 0x00  ; 0
  d4:  90 e0         ldi  r25, 0x00  ; 0
  d6:  08 95         ret

Da stimmen Theorie und Praxis dann übererein.

Oliver

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.