Forum: Compiler & IDEs Vergleich von zwei chars


von Thomas (Gast)


Lesenswert?

Hallo,
ich habe eine Frage zu folgendem:
1
char zeichen = 0xE4;    
2
if (zeichen == 0xE4) 
3
   printf ("Ist gleich");
4
else
5
   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?

von Michael G. (glunzl)


Lesenswert?

Hallo!

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

Gruß
Michael

von Thomas (Gast)


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?

von Stefan B. (stefan) Benutzerseite


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.

von Thomas (Gast)


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.

von Michael G. (glunzl)


Lesenswert?

Vor kurzem gehabt:

Beitrag "Problem bei If Bedingung"

Michael

von Thomas (Gast)


Lesenswert?

Demnach wäre
1
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).

von Karl H. (kbuchegg)


Lesenswert?

Thomas wrote:

>
1
> char zeichen = 0xE4;
2
> if (zeichen == 0xE4)
3
>    printf ("Ist gleich");
4
> else
5
>    printf ("Ist nicht gleich");
6
>
>
> 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.

von Peter D. (peda)


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

von Thomas (Gast)


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.

von Rolf Magnus (Gast)


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.

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.