Ist char standardmäßig signiert oder nicht signiert?

158

In dem Buch "Complete Reference of C" wird erwähnt, dass chares standardmäßig nicht signiert ist.

Ich versuche dies jedoch sowohl mit GCC als auch mit Visual Studio zu überprüfen. Es wird standardmäßig als signiert angenommen .

Welches ist korrekt?

C Lernender
quelle
5
Das einzige C-Nachschlagewerk, dem ich vertraue, ist Harbison & Steeles "C: A Reference Manual" ( careferencemanual.com ). Natürlich ist der Standard das letzte Wort, aber er ist nicht sehr gut lesbar und enthält nur die geringsten Informationen zu vorstandardisierten und allgemeinen (dh POSIX) Verwendungen, die außerhalb des Standards liegen. Harbison & Steele ist gut lesbar, detailliert und wahrscheinlich korrekter als die meisten Referenzen. Es ist jedoch auch kein Tutorial. Wenn Sie sich also in der Anfangsphase des Lernens befinden, ist es wahrscheinlich keine gute Sache, sich darauf einzulassen.
Michael Burr
15
Ich denke, das Buch, das Sie lesen, ist C: The Complete Reference von Herbert Schildt. Aus einer Rezension dieses Buches ( accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm ): Ich werde dieses Buch nicht empfehlen (zu viele von Ihnen geben meiner Meinung zu viel Gewicht), aber Ich denke nicht, dass es das gleiche Opprobrium verdient, das zu Recht auf einige seiner anderen Arbeiten geworfen wurde. Wie Michael sagt, ist Harbison & Steele eine viel bessere Referenz .
Alok Singhal
Meine zwei Cent hier: Da charvorzeichenlos sein kann, verwenden Sie als Faustregel a int, um einen Wert mit zu lesen getchar(), der möglicherweise zurückgegeben wird EOF. EOFwird normalerweise als -1oder als anderer negativer Wert definiert, dessen Speicherung in einem unsignednicht das ist, was Sie wollen. Hier ist die Erklärung: extern int getchar();Übrigens, diese Empfehlung stammt auch aus dem Buch "C: A Reference Manual".
Maxim Chetrusca
6
Die einzige C-Referenz, der ich vertraue, ist ISO / IEC 9899: 2011 :-)
Jeff
3
@MaxChetrusca guter Rat, aber schlechte Begründung: Selbst im signierten charFall müssten Sie intden Rückgabewert speichern.
Antti Haapala

Antworten:

204

Das Buch ist falsch. Der Standard gibt nicht an, ob Plain charsigniert oder nicht signiert ist.

Tatsächlich definiert die Norm drei verschiedene Arten: char, signed char, und unsigned char. Wenn Sie #include <limits.h>und dann schauen CHAR_MIN, können Sie herausfinden, ob Plain charist signedoder unsigned(wenn CHAR_MINkleiner als 0 oder gleich 0 ist), aber selbst dann unterscheiden sich die drei Typen in Bezug auf den Standard.

Beachten Sie, dass chardies auf diese Weise etwas Besonderes ist. Wenn Sie eine Variable deklarieren, intentspricht dies zu 100% der Deklaration als signed int. Dies gilt immer für alle Compiler und Architekturen.

Alok Singhal
quelle
1
@Alok: das gleiche gilt nicht für einige andere Datentypen, zum Beispiel intbedeutet signed intimmer, oder? Abgesehen davon char, in welchen anderen Datentypen gibt es die gleiche Verwirrung C?
Lazer
8
@eSKay: Ja, charist der einzige Typ, der signiert oder nicht signiert werden kann. intist zum signed intBeispiel äquivalent zu .
Alok Singhal
28
Es gibt einen hysterischen, ähm, historischen Grund dafür - zu Beginn des Lebens von C wurde der "Standard" mindestens zweimal umgedreht, und einige beliebte frühe Compiler landeten auf die eine und andere auf die andere Weise.
Hot Licks
9
@AlokSinghal: Es ist auch implementierungsdefiniert, ob ein Bitfeld vom Typ intsigniert oder nicht signiert ist.
Keith Thompson
@ KeithThompson danke für die Korrektur. Ich neige dazu, einige Details über Bitfeldtypen zu vergessen, da ich sie nicht oft benutze.
Alok Singhal
68

Wie Alok betont , überlässt der Standard dies der Implementierung.

Für gcc ist die Standardeinstellung signiert, aber Sie können dies mit ändern -funsigned-char. Hinweis: Für gcc in Android NDK ist die Standardeinstellung nicht signiert . Sie können auch explizit nach signierten Zeichen mit fragen -fsigned-char.

In MSVC ist die Standardeinstellung signiert, aber Sie können dies mit ändern /J.

R Samuel Klatchko
quelle
2
Interessant, dass Schildts Beschreibung nicht mit dem Verhalten von MSVC übereinstimmt, da seine Bücher normalerweise auf MSVC-Benutzer ausgerichtet sind. Ich frage mich, ob MS irgendwann die Standardeinstellung geändert hat.
Michael Burr
1
Ich dachte, es hängt nicht vom Compiler ab, sondern von der Plattform. Ich dachte, char wurde als dritter Typ von "Zeichendatentyp" belassen, um dem zu entsprechen, was die Systeme zu dieser Zeit als druckbare Zeichen verwendeten.
Spidey
10
GCC-Dokumente sagen, dass es maschinenabhängig ist: " Jeder Maschinentyp hat eine Standardeinstellung für das Zeichen. Es ist entweder standardmäßig wie ein Zeichen ohne Vorzeichen oder standardmäßig wie ein Zeichen mit Vorzeichen. "
Deduplicator
1
Können Sie bitte eine Quelle für Ihre Notiz angeben, dass auf Android der Standardwert ein Zeichen ohne Vorzeichen ist?
Phlipsy
1
@Spidey Der C-Standard unterscheidet nicht wirklich zwischen Compilern, Plattformen und CPU-Architekturen. Es fasst sie alle unter "Implementierung" zusammen.
Plugwash
35

C99 N1256 Entwurf 6.2.5 / 15 "Typen" hat Folgendes über die Signatur des Typs zu sagen char:

Die Implementierung muss char so definieren, dass es denselben Bereich, dieselbe Darstellung und dasselbe Verhalten wie signiertes oder nicht signiertes char hat.

und in einer Fußnote:

CHAR_MIN, definiert in <limits.h>, hat einen der Werte 0oder SCHAR_MIN, und dies kann verwendet werden, um die beiden Optionen zu unterscheiden. Unabhängig von der getroffenen Wahl charhandelt es sich um einen von den beiden anderen getrennten Typ, der mit beiden nicht kompatibel ist.

Michael Burr
quelle
7

Laut dem Buch The C Programming Language von Dennis Ritchie, dem De-facto-Standardbuch für ANSI C, sind Zeichen mit oder ohne Vorzeichen maschinenabhängig, aber druckbare Zeichen sind immer positiv.

Ravi Rathi
quelle
9
Es ist nicht unbedingt so, dass druckbare Zeichen immer positiv sind. Der C-Standard garantiert, dass alle Mitglieder des Basisausführungszeichensatzes nicht negative Werte haben.
Keith Thompson
7

Gemäß dem C-Standard ist die Signatur von normalem Zeichen "Implementierung definiert".

Im Allgemeinen wählten die Implementierer diejenige, die für die Implementierung in ihrer Architektur effizienter war. Auf x86-Systemen ist char im Allgemeinen signiert. Auf Arm-Systemen ist es im Allgemeinen nicht signiert (Apple iOS ist eine Ausnahme).

Plugwash
quelle
2
@plugwash Ihre Antwort wurde wahrscheinlich abgelehnt, weil Tim Post seine Schlüssel verloren hat . Im Ernst, Sie sollten sich keine Gedanken über eine einzelne Ablehnung machen, solange Sie sicher sind, dass Ihre Antwort richtig ist (was in diesem Fall der Fall ist). Es ist mir mehrmals passiert, dass meine Beiträge ohne triftigen Grund herabgestuft wurden. Mach dir keine Sorgen, manchmal machen die Leute einfach seltsame Dinge.
Donald Duck
1
Warum ist signiertes Zeichen auf x86 effizienter? Irgendwelche Quellen?
Martinkunev
2

Laut "The C ++ Programming Language" von Bjarne Stroustrup charist "Implementierung definiert". Dies kann signed charoder unsigned charhängt von der Implementierung ab. Mit können Sie überprüfen, ob charsigniert ist oder nicht std::numeric_limits<char>::is_signed.

BoQ
quelle
9
Dies ist eine C-Frage. C ++ ist eine andere Sprache, und C ++ - Referenzen haben keine Relevanz für C.
MM
1

Jetzt wissen wir, dass der Standard dies der Implementierung überlässt.

Aber wie Sie zu überprüfen , ein Typ ist signedoder unsignedwie char?

Ich habe dazu ein Makro geschrieben:

#define IS_UNSIGNED(t) ((t)~1 > 0)

und testen Sie es mit gcc, clangundcl . Aber ich bin mir nicht sicher, ob es für andere Fälle immer sicher ist.

南山 竹
quelle
Was ist falsch an gewöhnlichem CHAR_MIN <0 (oder WCHAR_MIN <0 für wchar_t)?
Öö Tiib