Moin, im Nachbarthread habe ich ja schon geäußert, dass ich die Unterscheidung "verwirrend" finde. Ich kann nachvollziehen, dass man die kleinste adressierbare Einheit, die in der CPU auch für Integerarithmetik benutzt wird, auf un/signed char gemapped wird. Ein zusätzlicher Datentyp <char> mit der gleichen Breite erscheint mir da redundant. Er könnte vielleicht sinnvoll sein wenn (fehlerträchtige) Operationen (+,-,<,>> etc.) nicht erlaubt wären (wie in anderen Sprachen), sind sie aber. Bei der Arbeit mit Zeicheintabellen wird mit Indizes gearbeitet, also nicht-negativen Zeichencodes, was für <unsigned char> sprechen würde. Bleibt die Argumentation den <char> als Zeichentyp zur Unterscheidung (besseren Lesbarkeit) von den Integertypen un/signed char zu führen. Das wird allerdings schnell unscharf wenn man trotzdem die o.g. (mathematischen) Operationen darauf durchführen darf und zudem un/signed char heutzutage in der STL (IOS) nicht als Integer sondern als Zeichen interpretiert werden. Kennt jemand den historischen Ursprung für den Datentyp <char>? Grüße, mikro77
:
Bearbeitet durch User
S. J. schrieb: > Ein zusätzlicher Datentyp <char> mit der gleichen Breite erscheint mir > da redundant. Inhaltlich ist er redundant. Aber speziell bei C++ merkt man sehr deutlich, dass man da mit 2 Typen nicht auskommt, sondern alle 3 benötigt. Ursächlicher Fehler ist, dass man sich beim Typ <char> in C nicht darauf festgelegt hatte, ob der nun signed oder unsigned sein soll, dieser Typ aber implizit auf Strings zutrifft. Wenn dann <char>, <signed char> und <unsigned char> nicht formal verschiedene Typen sind, dann wird Overloading massiv erschwert.
char ist je nach Compilervorliebe entweder ein signed char oder ein unsigned char. War ist daran unklar.
Als C erfunden wurde war es noch wenig relevant, ob mit oder ohne Vorzeichen. Damals waren das auch nur 2 Typen und <char> war entweder der eine oder der andere. Die Bedeutung der Sprache C entwickelte sich aber massegeblich über die PDP-11 Familie, und die kann mit Bytes erheblich besser umgehen, wenn die ein Vorzeichen haben.
... schrieb: > char ist je nach Compilervorliebe entweder ein signed char > oder ein unsigned char. > War ist daran unklar. Er erwähnte die STL, also geht es auch um C++. Und da trifft das eindeutig nicht zu. Inhaltlich gibt es zwar nur 2 Typen, formal sind aber <char *>, <signed char *>, <unsigned char *> 3 verschiedene Pointertypen.
> Und da trifft das > eindeutig nicht zu. Inhaltlich gibt es zwar nur 2 Typen, formal sind > aber <char *>, <signed char *>, <unsigned char *> 3 verschiedene > Pointertypen. Tja, sowas waere mir ja suspekt mit der Konsequenz sowas nicht zu benutzen.
... schrieb: > sowas waere mir ja suspekt mit der Konsequenz sowas nicht zu benutzen. Das ist definitiv ein Konstruktionsfehler von C. Aber "Hätte man damals nicht ..." hilft nicht weiter. Abgesehen von IBM kannten die Amis damals eben nur ASCII, und da reicht 0..127 aus.
:
Bearbeitet durch User
Die "signed"- oder "unsigned"-Frage ist weniger durch eine "Compilervorliebe" (was auch immer das sein soll) begründet, als durch konkrete Limitierung was die Plattform angeht. C-Compiler generieren letztendlich Binärcode. Dazu müssen sie die Assemblerbefehle verwenden, die die Plattform zur Verfügung stellt. Wenn die dann eben mit signed 8-Bit Arithmetik besser umgehen kann als mit unsigned, dann wird der default char Datentyp für diese Plattform eben signed (x86, Sparc, ...) und wenn das nicht der Fall ist, unsigned (PPC, ARM, ...). Da kann man sich drüber aufregen oder es bleiben lassen, es wird nix ändern. Wäre es nicht so, wie's ist, würde wahrscheinlich darüber lamentiert, daß irgendein Compiler für 8-Bit Arithmetik ständig "unnötige" sign-extends in den Binärcode reinfummelt oder mit "zu breiten" ints rechnet.
A. K. schrieb: > Inhaltlich ist er redundant. Aber speziell bei C++ merkt man sehr > deutlich, dass man da mit 2 Typen nicht auskommt, sondern alle 3 > benötigt. Werden wirklich alle 3 Varianten "benötigt"? Oder ist das lediglich ein Zugeständnis an die C Altlast? Man hätte prinzipiell auch alle Library Funktionen für Zeichen mit <unsigned char> definieren können, oder? Oder bietet <char> tatsächlich einen Mehrwert?!
S. J. schrieb: > Werden wirklich alle 3 Varianten "benötigt"? Oder ist das lediglich ein > Zugeständnis an die C Altlast? Andersrum. Das Problem tritt erst in C++ so richtig auf. Wenn du nur 2 Typen hast und in C++ Overloads verwendest void f(signed char *); void f(unsigned char *); dann weisst du nicht, welche davon bei f("Hallo") aufgerufen wird. Bei void f(char *); void f(signed char *); void f(unsigned char *); ist das hingegen eindeutig. Das geht aber nur bei 3 Typen.
:
Bearbeitet durch User
Markus F. schrieb: > C-Compiler generieren letztendlich Binärcode. Dazu müssen sie die > Assemblerbefehle verwenden, die die Plattform zur Verfügung stellt. Wenn > die dann eben mit signed 8-Bit Arithmetik besser umgehen kann als mit > unsigned, dann wird der default char Datentyp für diese Plattform eben > signed (x86, Sparc, ...) und wenn das nicht der Fall ist, unsigned (PPC, > ARM, ...). Das "gefällt" mir als historische Begründung bisher am Besten (paßt gut zur C-Historie).
S. J. schrieb: > Das "gefällt" mir als historische Begründung bisher am Besten (paßt gut > zur C-Historie). Wobei die Vorliebe für signed/unsigned nicht nur mit der bestehenden Zielmaschine zu tun hat. Da hatte sich über die PDP-11 eine gewisse Gewohnheit entwickelt, chars als signed anzusehen. Man hatte einen Haufen Quellcode von ebendort, bei dem man sich nicht sicher war, wie er sich bei unsigned verhält. Also hat man beispielsweise auch auf x86 einfach so weiter gemacht.
A. K. schrieb: > ... Die Implikationen sind mich durchaus bewußt. Mir geht es eher um die Sinnhaftigkeit des zusätzlichen <char> Typs im Rahmen der Sprachdefinition, die ich nicht wirklich sehe. Mit der historischen Deutung (als plattformabhängiger performanter Datentyp) kann ich aber zumindest "leben".
S. J. schrieb: > Ein zusätzlicher Datentyp <char> mit der gleichen Breite erscheint mir > da redundant. > ... > Kennt jemand den historischen Ursprung für den Datentyp <char>? Kurze Antwort: char ist älter als unsigned char und signed char. "Zusätzlich" vorhanden ist also nicht das char, sondern die beiden anderen char-Typen. Lange Antwort: Am Anfang, als die Welt (bzw. C) erschaffen wurde, was es noch ganz einfach: Es gab an elementaren Datentypen nur char, int, float und double, aber noch nicht dieses neumodische Zeugs wie signed, unsigned, long, short usw. (siehe C Reference Manual von Dennis M. Ritchie). Die Integer-Typen int und char waren beide vorzeichenbehaftet und wurden in Zweierkomplementdarstellung im Speicher abgelegt. Die verwendete Zeichencodierung (ASCII) umfasste nur 7 Bit, so dass man jedes Zeichen als nichtnegativen char-Wert darstellen konnte. Da es noch keinen verbindlichen Standard gab sind einige Compilerbauer von diesen Vorgaben abgewichen, weil es für ihre Rechnerarchitekturen günstiger war. Die einen haben für die vorzeichenbehafteten Zahlen die Einer- statt der Zweierkomplementdarstellung gewählt, weil die Rechnerhardware diese Darstellung verlangte. Andere haben aus dem vorzeichenbehafteten char ein vorzeichenloses gemacht. Ein Grund dafür könnte bspw. darin gelegen haben, dass die verwendete CPU keinen Befehl zur vorzeichenrichtigen Erweiterung eines Bytes in ein Wort hatte und deswegen für jede explizite oder implizite Konvertierung von char nach int eine Fallunterscheidung erforderlich gewesen wäre. Irgendwann kam dann das unsigned, zuerst nur für den Typ int, später (im ASNI-Standard) auch für alle anderen Integer-Typen. Bei int war jetzt klar: mit unsigned davor ist es vorzeichenlos, sonst vorzeichenbehaftet. Bei char ohne unsigned gab es je nach Plattform bzw. Compilerhersteller nach wie vor beide Möglichkeiten. Man wollte dies auch nicht ändern, weil sonst bestehende Software, die von einem bestimmten Verhalten von char aufbaute, nicht mehr funktioniert hätte. Also hat der ANSI-Standard zusätzlich zum klar definierten unsigned char und dem wankelmütigen char noch ein klar definiertes signed char hinzugefügt. Bei dieser Gelegenheit hat man das signed-Schlüsselwort auch für die anderen Integer-Typen erlaubt, obwohl es dort nicht nötig ist, weil es bereits den Default darstellt. Daran hat sich bis heute nichts mehr geändert. Wichtig zu wissen ist, dass char-Literale wie bspw. 'A' oder Zeichen in Stringliteralen wie "AAA" immer vom Typ char sind, weswegen es plattformabhängig ist, ob bspw. ein nach ISO/IEC 8859-1 codiertes 'Ä' in C den Wert 196 oder -60 hat. Deswegen ist es ratsam, char nur für Zeichen zu verwenden. Für 8-Bit Zahlen sollte man hingegen immer signed char oder unsigned char (oder auch einen passenden Typ aus stdint.h) nehmen, um bei Berechnungen plattformunabhängig zu sein.
Yalu X. schrieb: > Die einen haben für die vorzeichenbehafteten Zahlen die Einer- statt der > Zweierkomplementdarstellung gewählt, weil die Rechnerhardware diese > Darstellung verlangte. Gab es wirklich mal C-Compiler für solche Rechner?
Yalu X. schrieb: > Irgendwann kam dann das unsigned, zuerst nur für den Typ int, später (im > ASNI-Standard) auch für alle anderen Integer-Typen. Die unsigned Varianten der Integer-Typen gab es bereits in K&R C vor dem ANSI Standard, meiner Erinnerung nach auch das Keyword "signed". In der allerersten Sprachfassung, noch vor K&R, mag das anders gewesen sein. Unklar war damals aber noch, welche Variante sich z.B. auf 32-Bittern in (unsigned short)x + (int)y durchsetzt, sign preservation vs. value preservation nannte sich das. Das wurde erst in C89 geklärt.
:
Bearbeitet durch User
A. K. schrieb: > Yalu X. schrieb: >> Die einen haben für die vorzeichenbehafteten Zahlen die Einer- statt der >> Zweierkomplementdarstellung gewählt, weil die Rechnerhardware diese >> Darstellung verlangte. > > Gab es wirklich mal C-Compiler für solche Rechner? Das hatten wir hier erst vor kurzem: Die UNIVAC-Rechner und deren Söhne von Unisys, für die es auch einen C-Compiler und sogar Java gibt. A. K. schrieb: > Die unsigned Varianten der Integer-Typen gab es bereits in K&R C vor dem > ANSI Standard, meiner Erinnerung nach auch das Keyword "signed". In der > allerersten Sprachfassung, noch vor K&R, mag das anders gewesen sein. Kann sein, ich habe gerade keinen Zugriff auf einen alten K&R. Im "Rationale for International Standard — Programming Languages — C, Revision 5.10, April-2003" steht jedenfalls geschrieben:
1 | Several new types were added in C89: |
2 | |
3 | void |
4 | void* |
5 | signed char |
6 | unsigned char |
7 | unsigned short |
8 | unsigned long |
9 | long double |
10 | |
11 | And new designations for existing types were added: |
12 | |
13 | signed short for short |
14 | signed int for int |
15 | signed long for long |
Ich weiß allerdings nicht, auf welche Prä-C89-C-Version sich das "added" bezieht.
A. K. schrieb: > > Gab es wirklich mal C-Compiler für solche Rechner? Ich denke schon. Die Cyber 180 war eine solche Maschine. Die konnte sowohl mit Zweierkomplementen (NOS/VE) als auch mit Einerkomplementen (NOS wie beim Vorgängermodel Cyber 170) umgehen und einen C-Compiler gab's auch. War halt für Heimanwendungen nicht so verbreitet, mit so was wurde jahrzehntelang unser Wetter ausgerechnet ... http://www.computerwoche.de/a/us-anbieter-ersetzt-serie-170-durch-sechs-neue-modelle-control-data-verdoppelt-cyber-leistung,1174189 P.S.: und wenn ich mich ganz täusche, dann haben die "Cray-Wohnrechner" zumindest ihre Adressrechnung im Einerkomplement gemacht.
:
Bearbeitet durch User
Yalu X. schrieb: > Kann sein, ich habe gerade keinen Zugriff auf einen alten K&R. Korrektur - die Sprachdefinition kannte diese Typen zwar nicht, aber viele Compiler implementierten auch die übrigen "unsigned" Typen.
:
Bearbeitet durch User
Markus F. schrieb: > P.S.: und wenn ich mich ganz täusche, dann haben die "Cray-Wohnrechner" > zumindest ihre Adressrechnung im Einerkomplement gemacht. Ja, dass es im Umfeld von Cray solche Maschinen gab ist mir bewusst. Ich fragte mich eher, inwieweit dafür C als Programmiersprache existierte.
A. K. schrieb: > Ja, dass es im Umfeld von Cray solche Maschinen gab ist mir bewusst. Ich > fragte mich eher, inwieweit dafür C als Programmiersprache existierte. Für die Cray's gab's (fast) "normale" C-Compiler.
Markus F. schrieb: > Für die Cray's gab's (fast) "normale" C-Compiler. Als die Crays schon seinen Namen trugen arbeiteten sie bereits im Zweierkomplement. Es waren die vorherigen Crays von CDC, die im Einerkomplement arbeiteten, also CDC6600, CDC7600 und deren spätere Varianten.
:
Bearbeitet durch User
> Abgesehen von IBM kannten die Amis damals eben nur ASCII, und da reicht 0..127
aus.
ASCII war die Erlösung. Davor gab es 6..9 Bit pro Zeichen mit teils von
Rechnermodell zu Rechnermodell innerhalb einer Familie unterschiedlicher
Kodierung. Nur IBM hat noch 2..3 Jahrzehnte gebraucht, um sich von ihrem
Zone-Code der Lochkarten zu lösen.
Carl D. schrieb: >> Abgesehen von IBM kannten die Amis damals eben nur ASCII, und da reicht 0..127 > aus. > > ASCII war die Erlösung. EBCDIC und ASCII kamen praktisch zeitgleich. Aber bei EBCDIC wäre niemand auf die Idee gekommen, das in 8 Bits mit Vorzeichen zu codieren. Durchgesetzt hatte sich das 8-Bit Byte als universelle Daten- und Adressierungseinheit mit IBMs 360 Familie in den 60ern.
:
Bearbeitet durch User
Die 8 Bit, ja, die hatten sich durchgesetzt, auch wenn wir heute eher bei WCHAR sind als 16 Bit. IBM hat mit EBCDIC eher versucht ihr Lochkartenformat rüberzuretten. Und andere schräge Sachen gemacht. Z.B. das durchgestrichene O um es von der Zahl 0 unterscheiden zu können. Als auf den Kisten Assembler lernte, nach einem Jahrzehnt ASCII-Zeichensatz, hab ich mich über den Befehl "null" gewundert bis ich verstanden hatte, daß das "OR" bedeuten sollte. Ansonsten ein schöne Zeit und mehr mit Assembler zu verdienen als auf Mainframes, war damals und ist heute kaum vorstellbar.
A. K. schrieb: > S. J. schrieb: >> Ein zusätzlicher Datentyp <char> mit der gleichen Breite erscheint mir >> da redundant. > > Inhaltlich ist er redundant. Aber speziell bei C++ merkt man sehr > deutlich, dass man da mit 2 Typen nicht auskommt, sondern alle 3 > benötigt. Leider macht sich die C++ Standardbibliothek das nicht zunutze. Bei einem std::ostream werden char, signed char und unsigned char immer als Zeichen ausgegeben. Konsequenter wäre, die signed/unsigned-Variante als Zahl auszugeben und nur die reinen chars als Zeichen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.