Javas byte in C++(11) - ein char-Wrapper
-
Shade Of Mine schrieb:
wenn ich ein
cout<< format("%d") % 'a';
mache, bekomme ich eine Zahl als Ergebnis.Und was kommt raus wenn man
unsigned char uc = 123; cout<< format("%1%") % uc;macht?
Es ist einfach nur oft praktisch wenn man cout<<'a'; macht, dass ein a ausgegeben wird - deshalb ist das bei der iostream library der Fall.
'a' ist ein
char.chars sollen natürlich als Zeichen ausgegeben werden. Aber warum zum Geier werdensigned charundunsigned charals Zeichen ausgegeben?Es hindert dich aber nichts daran eine Library zu schreiben wo das nicht der Fall ist.
Sinnfreier Beitrag. Klar kann man alles selber schreiben.
Man darf aber auch mal fragen warum was so ist wie es ist. Bzw. anmerken dass es doof ist so wie es ist.
Und das ist es.
Also doof.
So wie es ist.
-
hustbaer schrieb:
Sinnfreier Beitrag. Klar kann man alles selber schreiben.
Man darf aber auch mal fragen warum was so ist wie es ist. Bzw. anmerken dass es doof ist so wie es ist.
Und das ist es.
Also doof.
So wie es ist.Es ist kein bisschen doof. Das verhalten ist wahnsinnig praktisch. Denn wenn wir char immer automatisch als int ausgeben wuerden, wuerdest du recht schnell sehen dass das ziemlich nervig wird wenn du mit strings hantieren willst.
Fuer die wenigen situationen wo man es anders haben will gibt es die richtigen Tools.
Deshalb nochmal:
dass ein char oft als Buchstabe interpretiert wird (merke: Interpretiert, er ist keiner, er wird noch als einer interpretiert) ist enorm praktisch und spart viel Arbeit. Deshalb macht man es in der Regel (merke: in der Regel, also meistens aber nicht immer) so. Es gibt aber keinen Zwang. Die Libraries muessen eins von beiden machen - das ist nunmal so. Und sie machen das, was meistens besser ist. Gleichzeitig bieten sie aber auch eine Moeglichkeit an es anders zu haben wenn man denn will.Und es spricht nichts gegen eine Library die es standardmaessig andersherum macht. Bis auf, dass sie enorm unpraktisch waere.
Man muss naemlich die Konsequenzen betrachten. Nur sagen: es waere toll wenn immer das passiert was ich will - das ist kurzsichtig.
Andere Sprachen umgehen das Problem, indem sie einen string als primitiven Typ haben und 'a' ist dann ein string der laenge 1. Das funktioniert in C++ aber nicht.
-
Nur um es noch mal klar zu machen:
charist und wird als integraler Skalar behandelt. BIS auf die Ein/Ausgabe.Ich fand aber dieses Problem gerade zum kotzen. Ich kann doch nicht einfach so
for(char a(65);a < 70;++a) //....schreiben, wenn ich weiß, dass es nicht intern 65, 66, 67, 68, 69, 70 wird sondern
'A', 'B', 'C', 'D', 'E', 'F'. Das ist eben ein Tick von mir. Wenn ich nicht den Gedanken hätte, wäre alles im Lot.Ich dachte, die Raumfolgearithmetik (also das Zweierkomplement) funktioniert auch übertragbar zwischen den Skalaren. Ist dem nicht so?
hustbaers Vorschlag finde ich richtig.
charwird eigentlich nur als Zeichen benutzt, wenn man es so schreibt. Wenn ich explizit die Vorzeichenbehaftung angebe, dann ist doch klar dass ich es als integralen Zähler o. ä. verwenden will..
-
Hacker schrieb:
Nur um es noch mal klar zu machen:
charist und wird als integraler Skalar behandelt. BIS auf die Ein/Ausgabe.Ich fand aber dieses Problem gerade zum kotzen. Ich kann doch nicht einfach so
for(char a(65);a < 70;++a) //....schreiben, wenn ich weiß, dass es nicht intern 65, 66, 67, 68, 69, 70 wird sondern
'A', 'B', 'C', 'D', 'E', 'F'. Das ist eben ein Tick von mir. Wenn ich nicht den Gedanken hätte, wäre alles im Lot.Ich dachte, die Raumfolgearithmetik (also das Zweierkomplement) funktioniert auch übertragbar zwischen den Skalaren. Ist dem nicht so?
hustbaers Vorschlag finde ich richtig.
charwird eigentlich nur als Zeichen benutzt, wenn man es so schreibt. Wenn ich explizit die Vorzeichenbehaftung angebe, dann ist doch klar dass ich es als integralen Zähler o. ä. verwenden will..
Das ist mir zu kryptisch.
Verstehe auch das Problem generell nicht.
Man zeige bitte realistischen Code, der komplexer wird, weil Zeichen als Zeichen ausgegeben werden.
-
camper schrieb:
Das ist mir zu kryptisch.Du bist camper.

Ich hab auch nicht zu deinem TMP-Zeug tl:dr geschrieben.
-
Shade Of Mine schrieb:
hustbaer schrieb:
Sinnfreier Beitrag. Klar kann man alles selber schreiben.
Man darf aber auch mal fragen warum was so ist wie es ist. Bzw. anmerken dass es doof ist so wie es ist.
Und das ist es.
Also doof.
So wie es ist.Es ist kein bisschen doof. Das verhalten ist wahnsinnig praktisch. Denn wenn wir char immer automatisch als int ausgeben wuerden, wuerdest du recht schnell sehen dass das ziemlich nervig wird wenn du mit strings hantieren willst.
(...)
Ich hab's jetzt glaub ich erst 2x geschrieben, also zum 3. Mal:
char,signed charundunsigned charsind bereits drei verschiedene Typen.
Was wäre nun so unpraktisch daran wennsigned charundunsigned charals Integers ausgegeben würden, und nurcharweiterhin als Zeichen?Aufwand würde das auch keinen darstellen, alles was dafür nötig wäre ist zwei Spezialisierungen des Stream-Insert Operators auf die "Integer" Variante umzubiegen. Die muss es sowieso schon geben, für die anderen Typen (
short,intetc.), die eben als Integer ausgegeben werden.
Und das selbe nochmal für den Stream-Extraction Operator.
-
camper schrieb:
Man zeige bitte realistischen Code, der komplexer wird, weil Zeichen als Zeichen ausgegeben werden.
template <class MyCounterType> class MySizeOptimizedDataStructure { public: void Dump(std::ostream& os) { os << m_counter; } private: // ... MyCounterType m_counter; }; MySizeOptimizedDataStructure<unsigned char> foo; MySizeOptimizedDataStructure<long long> fooll; MySizeOptimizedDataStructure<__int128> foo128; // ...
-
Vielleicht muss ich ein Beispiel bringen:
Am Output vom ersten Aufruf würde ich nix ändern.
Der Output des Zweiten und Dritten ist aber IMO unsinnig, da sollte IMO "66" stehen statt "B".Was wäre daran unpraktisch?
-
hustbaer schrieb:
Ich hab's jetzt glaub ich erst 2x geschrieben, also zum 3. Mal:
char,signed charundunsigned charsind bereits drei verschiedene Typen.
Was wäre nun so unpraktisch daran wennsigned charundunsigned charals Integers ausgegeben würden, und nurcharweiterhin als Zeichen?Die Tatsache, dass vermutlich eine Menge existierender Code aufhört, vernünftig zu funktionieren.
Und einen überzeugenden Vorteil sehe ich nicht. Wäre die Implementation bereits so, wie du vorschlägst, hätte ich auch kein Problem damit, mit Sicherheit gäbe es dann irgendwann auch einen Thread in dem genau die andere Variante gefordert wird.
Warum jemand numerische Ein-/Ausgabe mit (u/s) chars betreiben möchte, erschliesst sich mir sowieso nicht. Es gibt schon mindestens 8 andere Integertypen, mit denen man das tun kann. Und wenn es unbedingt sein muss, kann man sich den entsprechenden Manipulator dafür ganz einfach selbst in 3 Zeilen schreiben.
-
@camper
Mir ist klar dass es jetzt ein Breaking-Change wäre der vermutlich viel Code betrifft. Ich schlage auch nicht vor es zu ändern.Mit ...
Würde mich mal interessieren warum das nicht gemacht wurde. Kann mir nämlich grad keinen wirklich guten Grund vorstellen.
... meinte ich warum das damals als die iostreams implementiert/definiert wurden so gemacht wurde.
BTW: weisst du woher die Dreiteilung char/signed char/unsigned char kommt? Kam das schon von C oder hat das C++ eingeführt?
-
hustbaer schrieb:
BTW: weisst du woher die Dreiteilung char/signed char/unsigned char kommt? Kam das schon von C oder hat das C++ eingeführt?
Ist eine alte C-Angelegenheit.
ARM schrieb:
3.6.1 Fundamental Types
...An implementation must specify whether the high-order bit of a char object that is neither explicitly signed nor unsigned is treated as a sign bit. Generally, the treatment chosen will take advantage of the instructions the target hardware executes most efficiently. Leaving this aspect of the language implementation-dependent is a common source of portability problems. Resolving these problems by simply defining chars to be unsigned (or signed) would lead to incompatibilities with C, however, and programmers rightfully expect C compatibility in such basic matters.
-
hustbaer schrieb:
Was wäre nun so unpraktisch daran wenn
signed charundunsigned charals Integers ausgegeben würden, und nurcharweiterhin als Zeichen?ganz einfach:
void write(unsigned char* bytes, size_t len, ostream& out) { while(len--) out<<*bytes++; }baemm! broken.
Obwohl ich doch eigentlich extra unsigned char genommen habe, weil ich ja eben wirklich auf bytes operiere und nicht auf buchstaben.
Hast du zu deinem Beispiel auch etwas echtes? wenn man auf die groesse optimiert arbeitet man idR nur auf bytes und wenn nicht, dann ist der Code dennoch komplexer weil man zB einen einen 100byte Datentyp eh nicht trivial ausgeben kann.
PS:
die einzige Situation wo man mehrere ziffern fuer 1 Byte haben will ist bei Ausgaben fuer Menschen. Und das ist etwas, das sehr selten vorkommt. Und wenn es vorkommt ist es einfach viel simpler die passende Methode zu verwenden. Vorallem weil man dann ja vielleicht doch lieber hex statt dec haben will...Wenn du einen 1 byte integer typ willst, weil short zu gross ist - das kann ich wiederum verstehen. ich wuesste zwar keine situation wo das wirklich etwas bringt - aber den Wunsch kann ich verstehen.
Nur bytes als mehrere Ziffern repraesentieren ist halt einfach unpraktisch.
-
@Shade Of Mine
Ich mag jetzt nicht auf alles einzeln eingehen was du geschrieben hast.Der Grossteil davon ist nur relevant bzw. macht nur Sinn mann man ignoriert was ich nun schon mehrfach geschrieben habe, nämlich dass mir klar ist dass man es jetzt nicht mehr ändern kann.
Ich stelle nur die Frage warum es nicht von Anfang an anders gemacht wurde. Was hier anscheinend als Rumnörgeln misverstanden wird, oder als Aufforderung oder sonstwas. So war es aber nie gemeint. Ich verstehe nur ganz ganz ehrlich nicht was der Grund war warum es so gemacht wurde wie es jetzt eben ist.
PS:
die einzige Situation wo man mehrere ziffern fuer 1 Byte haben will ist bei Ausgaben fuer Menschen. Und das ist etwas, das sehr selten vorkommt. Und wenn es vorkommt ist es einfach viel simpler die passende Methode zu verwenden. Vorallem weil man dann ja vielleicht doch lieber hex statt dec haben will...
Und was ändert sich wenn ich "1 Byte" in dieser Aussage durch "ein [beliebiger Integer Typ]" ersetze?
Davon abgesehen: die iostreams << operatoren formatieren halt nunmal per Default, und zwar "human readable". (*) Wieso sollten sie genau drei Typen unformatiert ausgeben? Noch dazu wo es dafür spezielle Funktionen gibt (write, put)? Nönönönö so wird da kein Schuh draus.Wenn du einen 1 byte integer typ willst, weil short zu gross ist - das kann ich wiederum verstehen.
Genau das ist doch der Knackpunkt: es GIBT diesen kleinen Integer Typ, bzw. sogar drei davon.
C++ als Sprache behandelt
unsigned charbzw.signed charauch nicht anders als andere Integer-Typen (mit einigen unwesentlichen Ausnahmen wie z.B. der Erlaubnis sämtliche PODs auch alsunsigned charlesen zu dürfen). Und selbstcharhat keine so krasse Sonderstellung, auch bloss ein paar zusätzliche Garantien bzw. Erlaubnisse sowie die Möglichkeit Character- bzw. String-Literale zu verwenden.Nur die
iostreamsLibrary meint hier Dinge einfach komplett anders machen zu müssen. Warum auch immer.*:
Für Serialisierung/Deserialisierung sind die iostreams nicht wirklich zu gebrauchen. Pack mal zwei Integers direkt hintereinander in einen Stream, und dann versuch' die wieder zu trennen. Und für raw IO gibt es wie gesagt eigene Funktionen.
-
hustbaer schrieb:
Davon abgesehen: die iostreams << operatoren formatieren halt nunmal per Default, und zwar "human readable". (*) Wieso sollten sie genau drei Typen unformatiert ausgeben? Noch dazu wo es dafür spezielle Funktionen gibt (write, put)? Nönönönö so wird da kein Schuh draus.
Weil du dann folgendes Problem hast:
Wie gibst du ein byte korrekt aus?vergleiche out.put('c') mit out<<'c'
Dann hast du plötzlich sehr schnell unterschiedliche Ausgaben. Das würde zu einer Menge komplizierten Code führen.Nochmal: die Situationen in denen du 1 Byte als mehrere Bytes repräsentieren willst, sind sehr gering. Ich habe das zB in reellen Code noch nie gebraucht.
Es würde aber vielen Code erschweren. Denn sobald du eben nicht human readable etwas darstellen willst - und ein byte human readable wäre hex korrekt und nicht dec (!) - dann ist es enorm unpraktisch.
Vorallem weil der Code dann unintuitiv wird.
Ich arbeite die ganze Zeit mit byte (unsigned char) - nur wenn ich es in eine Dateischreiben will, muss ich plötzlich nach char casten? Das macht die Sache unnötig kompliziert.unsigned char muss, wenn es ausgegeben wird genau 1 Byte entsprechen - sonst verkomplizierst du Code enorm.
Und char ist einfach praktisch als Buchstabe zu interpretieren.
Deshalb hat man sich dazu entschieden.
Schaumal: du schaffst nichtmal ein Beispiel zu konstruiieren wo es anders besser wäre. Wenn das mal nicht Beweis genug ist, dass es gut so ist, wie es ist...Und ich rede nicht von bestehenden Code. Das habe ich nicht mit einem Wort irgendwo erwähnt. Ich erkläre dir, dass man es so gemacht hat, weil es keine sinnvolle andere Variante gibt. Deine Idee würde nämlich die Codekomplexität erhöhen ohne reellen gewinn zu bringen.
-
@SoM: Nein, wenn du ein zeichen in die Datei schreiben wolltest, würdest du .write() verwenden, so wie für alle anderen Typen auch. hustbaer hat da schon Recht. Es wäre nur konsistent und logisch, dass sich operator << für (un)signed char gleich verhält wie die anderen.
-
Shade Of Mine schrieb:
Deshalb hat man sich dazu entschieden.
Ich glaube nicht dass du weisst wieso man sich so entschieden hat.
Schaumal: du schaffst nichtmal ein Beispiel zu konstruiieren wo es anders besser wäre. Wenn das mal nicht Beweis genug ist, dass es gut so ist, wie es ist...
Schaumal lieber Shade, wenn du lesen und verstehen könntest wäre dir aufgefallen dass ich bereits Beispiele gebracht habe. Aber du kannst diese natürlich gerne weiter ignorieren.
Und ich rede nicht von bestehenden Code. Das habe ich nicht mit einem Wort irgendwo erwähnt. Ich erkläre dir, dass man es so gemacht hat, weil es keine sinnvolle andere Variante gibt. Deine Idee würde nämlich die Codekomplexität erhöhen ohne reellen gewinn zu bringen.
Jo.
Blödsinn.
Genau umgekehrt.