mikrocontroller.net

Forum: Compiler & IDEs Vergleich von zwei chars


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe eine Frage zu folgendem:
char zeichen = 0xE4;    
if (zeichen == 0xE4) 
   printf ("Ist gleich");
else
   printf ("Ist nicht gleich");
Ergebnis:

Ist nicht gleich

Aber warum? Lasse ich mir mit sprintf den hexadezimalen Wert von zeichen 
ausgeben, so hat dieser 0xFFFFFFE4.
Der Compiler gibt mir zwar auch eine Warnung aus, dass der Vergleich 
immer false ist, aber ist denn in einem 8-Bit Char die 
Zweierkomplementdarstellung von negativen Zeichen anders?

Ein char ist ein char ist ein char, oder etwa nicht?

Autor: Michael Glunz (glunzl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Char geht von -128 bis + 127 dez. Versuch mal
unsigned char zeichen = 0xE4
 oder gleich den Typen uint8_t.

Gruß
Michael

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, 0xE4 hat den Wert -28. Wenn ich an beiden Stellen -28 anstatt 0xE4 
schreibe klappt der Vergleich.
Ich muss char verwenden, da die gesamte Funktion einzelne Zeichen eines 
Strings vergleicht (genauer: es werden die Umlaute eines Strings vom DOS 
zum Windows Format konvertiert).

Es sieht so aus, als ob im if-Vergleich die beiden chars auf 32-Bit 
aufgeblasen werden, und weil festgestellt wird dass die Werte negativ 
sind, werden auch alle anderen Bits gesetzt sodass die 0xFFs zu sehen 
sind.

Wo findet man das denn im C-Standard?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achte auf die Warnung, die der Compiler in der Zeile mit dem if ausgibt. 
Wenn keine Warnung ausgegeben wird, kontrolliere und ändere die 
Warneinstellungen des Compilers bis die Warnung erscheint. Das 
erleichtert das Programmieren. Wenn das nicht möglich ist, wechsele den 
Compiler.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bekomme ja eine Warnung vom Compiler wie ich oben beschrieb.

Wenn ich im Vergleich einen Cast nach char, also (char)0xE4 mache 
funktioniert es auch.
Scheint so als wenn bei der Variablendeklaration automatisch ein Cast 
durchgeführt wird.

Autor: Michael Glunz (glunzl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vor kurzem gehabt:

Beitrag "Problem bei If Bedingung"

Michael

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Demnach wäre
if (zeichen == (char) 0xE4)
also die Version, die auf allen Rechnerarchitekturen das richtige 
Ergebnis liefert (wenn man annimmt, dass ich mit der Konstante 0xE4 eine 
negative Zahl meinte).

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

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:

>
> char zeichen = 0xE4;
> if (zeichen == 0xE4)
>    printf ("Ist gleich");
> else
>    printf ("Ist nicht gleich");
> 
>
> Aber warum?
> aber ist denn in einem 8-Bit Char die
> Zweierkomplementdarstellung von negativen Zeichen anders?

Zuallererst ist 0xE4 nich vom Datentyp char, sondern immer
noch ein int.

Somit steht beim Vergleich

  if( zeichen == 0xE4 )

auf der linken Seite ein char und auf der rechten Seite ein int.
Die C-Regeln fordern, dass in so einem Fall zunächst mal alles
auf den gleichen Datentyp gebracht wird, in diesem Fall ein int.

Ergo wird der Inhalt von Zeichen von char auf int hochgecastet.
Da zeichen aber ein char ist und char auf deinem System anscheinend
ein signed char ist, wird aus der negativen 8-Bit Zahl 0xE4
die signed 16-Bit Zahl 0xFFE4. (Bei 2 Byte int).

Auf der anderen Seite steht der int 0xE4. In 2 Byte Schreibweise
für einen int also 0x00E4.
Damit lautet der Vergleich

  if( 0xFFE4 == 0x00E4 )

und das ist natürlich nicht wahr.

> Ich muss char verwenden, da die gesamte Funktion einzelne Zeichen eines
> Strings vergleicht (genauer: es werden die Umlaute eines Strings vom DOS
> zum Windows Format konvertiert).

Das ist kein Argument.
Das kann man immer auch so formulieren, dass anstelle von char
ein unsigned char vorkommt, womit man die Probleme mit der
Vorzeichenerweiterung, wenn ein impliziter cast auf int
passiert, umgehen kann.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richtig ist es natürlich, Strings und Zeichen immer als unsigned char zu 
definieren, es gibt ja keine negativen Buchstaben.

Blöd ist nur, daß bei der Erfindung von C nur 7Bit Zeichen üblich waren 
und deshalb die Stringfunktionen alle vom Typ char sind.
Da hilft dann nur casten, sobald man Bibliotheksfunktionen benutzt.

Eine saubere Lösung gibt es leider nicht.


Peter

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal Danke für die weiteren Erläuterungen.

Bis jetzt wird der Funktion eine Referenz auf std::string übergeben. 
Eine Instanz dieser Klasse ist im Normalfall vom Typ char (wurde wohl 
aus Kompatibilitätsgründen zu C so beibehalten).

Für die Verwendung von unsigned char müsste man dann wohl std::vector 
nehmen.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Richtig ist es natürlich, Strings und Zeichen immer als unsigned char
> zu definieren, es gibt ja keine negativen Buchstaben.

Nein. Richtig ist, sie als char zu definieren, denn das ist der Typ, der 
dafür gedacht ist. Ob der ein Vorzeichen hat oder nicht, kann dir dabei 
vollkommen egal sein, solange du es nur für Zeichen einsetzen willst. 
Das Problem von Thomas kam dadurch zustande, daß er direkt einen 
Integerwert reingeschrieben hat und kein Zeichen. Da spielt das 
Vorzeichen natürlich eine Rolle.

> Blöd ist nur, daß bei der Erfindung von C nur 7Bit Zeichen üblich waren
> und deshalb die Stringfunktionen alle vom Typ char sind.

??

> Eine saubere Lösung gibt es leider nicht.

Doch. char für Zeichen nehmen, signed/unsigned char, wenn man es als 
integer verwenden möchte.

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.