Hin und wieder weist jemand auf SO darauf hin, dass char
(auch bekannt als "Byte") nicht unbedingt 8 Bits sind .
Es scheint, dass 8-Bit char
fast universell ist. Ich hätte gedacht, dass es für Mainstream-Plattformen notwendig ist, ein 8-Bit char
zu haben, um seine Lebensfähigkeit auf dem Markt sicherzustellen.
Welche Plattformen verwenden jetzt und in der Vergangenheit eine char
, die nicht 8 Bit beträgt, und warum sollten sie sich von den "normalen" 8 Bit unterscheiden?
Welche Überlegungen sollten beim Schreiben von Code und beim Nachdenken über plattformübergreifende Unterstützung (z. B. für allgemein verwendete Bibliotheken) Plattformen mit Nicht-8-Bit-Funktionen berücksichtigt werden char
?
In der Vergangenheit bin ich auf einige DSPs von Analog Devices gestoßen, für die char
16 Bit verfügbar sind. DSPs sind wohl eine Art Nischenarchitektur. (Andererseits übertraf der handcodierte Assembler zu dieser Zeit leicht die Möglichkeiten der verfügbaren C-Compiler, sodass ich auf dieser Plattform nicht wirklich viel Erfahrung mit C gesammelt habe.)
quelle
Antworten:
char
ist auch 16 Bit auf den Texas Instruments C54x DSPs, die zum Beispiel in OMAP2 aufgetaucht sind. Es gibt andere DSPs mit 16 und 32 Bitchar
. Ich glaube, ich habe sogar von einem 24-Bit-DSP gehört, aber ich kann mich nicht erinnern, was, also habe ich es mir vielleicht vorgestellt.Eine weitere Überlegung ist, dass POSIX Mandate
CHAR_BIT == 8
. Wenn Sie also POSIX verwenden, können Sie davon ausgehen. Wenn jemand später Ihren Code auf eine nahezu Implementierung von POSIX portieren muss, hat dies zufällig die von Ihnen verwendeten Funktionen, aber eine andere Größechar
, das ist sein Pech.Im Allgemeinen denke ich jedoch, dass es fast immer einfacher ist, das Problem zu umgehen, als darüber nachzudenken. Geben Sie einfach ein
CHAR_BIT
. Wenn Sie einen genauen 8-Bit-Typ wünschen, verwenden Sieint8_t
. Ihr Code kann bei Implementierungen, die keine bereitstellen, geräuschvoll kompiliert werden, anstatt stillschweigend eine Größe zu verwenden, die Sie nicht erwartet haben. Zumindest würde ich es behaupten, wenn ich auf einen Fall stoßen würde, in dem ich einen guten Grund hatte, ihn anzunehmen.quelle
assert()
(wenn Sie das gemeint haben) würde ich#if CHAR_BIT != 8
...#error "I require CHAR_BIT == 8"
...#endif
static_assert()
?Es ist nicht so sehr, dass es sich lohnt, über etwas nachzudenken, sondern dass es sich an die Regeln hält. In C ++ sagt der Standard beispielsweise, dass alle Bytes "mindestens" 8 Bits haben. Wenn Ihr Code davon ausgeht, dass Bytes genau 8 Bit haben, verstoßen Sie gegen den Standard.
Das mag jetzt albern erscheinen - " Natürlich haben alle Bytes 8 Bits!", Höre ich Sie sagen. Aber viele sehr kluge Leute haben sich auf Annahmen verlassen, die keine Garantien waren, und dann ist alles kaputt gegangen. Die Geschichte ist voll von solchen Beispielen.
Zum Beispiel gingen die meisten Entwickler Anfang der 90er Jahre davon aus, dass eine bestimmte No-Op-CPU-Zeitverzögerung, die eine feste Anzahl von Zyklen benötigt, eine feste Taktzeit in Anspruch nehmen würde, da die meisten Consumer-CPUs in etwa gleich leistungsfähig waren. Leider wurden Computer sehr schnell schneller. Dies führte zur Entstehung von Boxen mit "Turbo" -Tasten - deren Zweck ironischerweise darin bestand, den Computer zu verlangsamen, damit Spiele mit der Zeitverzögerungstechnik mit einer angemessenen Geschwindigkeit gespielt werden konnten.
Ein Kommentator fragte, wo im Standard steht, dass char mindestens 8 Bits haben muss. Es ist in Abschnitt 5.2.4.2.1 . Dieser Abschnitt definiert
CHAR_BIT
die Anzahl der Bits in der kleinsten adressierbaren Entität und hat einen Standardwert von 8. Außerdem heißt es:Daher ist jede Zahl gleich 8 oder höher für die Substitution durch eine Implementierung in geeignet
CHAR_BIT
.quelle
char
mehr als 64 von ihnen darstellbar sein müssen, aber weniger als 128, also würden 7 Bits ausreichen.Maschinen mit 36-Bit-Architekturen haben 9-Bit-Bytes. Laut Wikipedia gehören zu Maschinen mit 36-Bit-Architekturen :
quelle
Einige davon sind mir bekannt:
quelle
char
Typ wirklich überhaupt nicht unterstützt ? Ich weiß, dass die Systembibliotheken nur die Wide-Char-Versionen von Funktionen unterstützen, die Zeichenfolgen enthalten, und dass zumindest einige Versionen von WinCE die ANSI-Zeichenfolgenfunktionen wie strlen entfernt haben, um zu verhindern, dass Sie Zeichenfolgen verarbeiten. Aber hatte es wirklich überhaupt keinen Char-Typ? Was warsizeof(TCHAR)
? Welchen Typ hat Malloc zurückgegeben? Wie wurde der Java-byte
Typ implementiert?Es gibt keinen vollständig portablen Code. :-)
Ja, es kann verschiedene Byte- / Zeichengrößen geben. Ja, es gibt möglicherweise C / C ++ - Implementierungen für Plattformen mit sehr ungewöhnlichen Werten von
CHAR_BIT
undUCHAR_MAX
. Ja, manchmal ist es möglich, Code zu schreiben, der nicht von der Zeichengröße abhängt.Fast jeder echte Code ist jedoch nicht eigenständig. Beispielsweise schreiben Sie möglicherweise einen Code, der Binärnachrichten an das Netzwerk sendet (Protokoll ist nicht wichtig). Sie können Strukturen definieren, die erforderliche Felder enthalten. Dann müssen Sie es serialisieren. Nur das binäre Kopieren einer Struktur in einen Ausgabepuffer ist nicht portierbar: Im Allgemeinen kennen Sie weder die Bytereihenfolge für die Plattform noch die Ausrichtung der Strukturelemente, sodass die Struktur nur die Daten enthält, aber nicht beschreibt, wie die Daten serialisiert werden sollen .
OK. Sie können Transformationen der Bytereihenfolge durchführen und die Strukturelemente (z. B.
uint32_t
oder ähnliches) mithilfememcpy
in den Puffer verschieben. Warummemcpy
? Weil es viele Plattformen gibt, auf denen es nicht möglich ist, 32-Bit (16-Bit, 64-Bit - kein Unterschied) zu schreiben, wenn die Zieladresse nicht richtig ausgerichtet ist.Sie haben also bereits viel getan, um Portabilität zu erreichen.
Und jetzt die letzte Frage. Wir haben einen Puffer. Die Daten davon werden an das TCP / IP-Netzwerk gesendet. Ein solches Netzwerk nimmt 8-Bit-Bytes an. Die Frage ist: Von welchem Typ sollte der Puffer sein? Wenn Ihre Zeichen 9-Bit sind? Wenn sie 16-Bit sind? 24? Vielleicht entspricht jedes Zeichen einem 8-Bit-Byte, das an das Netzwerk gesendet wird, und es werden nur 8 Bit verwendet? Oder sind mehrere Netzwerkbytes in 24/16/9-Bit-Zeichen gepackt? Das ist eine Frage, und es ist kaum zu glauben, dass es eine einzige Antwort gibt, die in alle Fälle passt. Viele Dinge hängen von der Socket-Implementierung für die Zielplattform ab.
Also, wovon ich spreche. Normalerweise kann Code bis zu einem gewissen Grad relativ leicht portierbar gemacht werden . Dies ist sehr wichtig, wenn Sie den Code auf verschiedenen Plattformen verwenden möchten. Die Verbesserung der Portabilität über diese Maßnahme hinaus erfordert jedoch viel Aufwand und ist häufig wenig sinnvoll , da der tatsächliche Code fast immer von anderem Code abhängt (Socket-Implementierung im obigen Beispiel). Ich bin sicher, dass für etwa 90% des Codes die Fähigkeit, auf Plattformen mit anderen Bytes als 8-Bit zu arbeiten, fast nutzlos ist, da eine Umgebung verwendet wird, die an 8-Bit gebunden ist. Überprüfen Sie einfach die Bytegröße und führen Sie die Bestätigung der Kompilierungszeit durch. Für eine höchst ungewöhnliche Plattform müssen Sie mit ziemlicher Sicherheit viel umschreiben.
Aber wenn Ihr Code sehr "eigenständig" ist - warum nicht? Sie können es so schreiben, dass unterschiedliche Bytegrößen möglich sind.
quelle
unsigned char
Wert gespeichert wird, sollten keine Portabilitätsprobleme auftreten, es sei denn, der Code verwendet Aliasing-Tricks anstelle von Verschiebungen, um Oktettsequenzen in / von größeren Ganzzahltypen zu konvertieren. Persönlich denke ich, dass der C-Standard Eigenheiten definieren sollte, um Ganzzahlen aus Sequenzen kürzerer Typen (am typischstenchar
) zu packen / zu entpacken, wobei eine feste garantierte verfügbare Anzahl von Bits pro Element (8 prounsigned char
, 16 prounsigned short
oder 32 prounsigned long
) gespeichert wird .Es scheint, dass Sie immer noch einen IM6100 (dh einen PDP-8 auf einem Chip) aus einem Lager kaufen können . Das ist eine 12-Bit-Architektur.
quelle
Viele DSP-Chips haben 16- oder 32-Bit
char
. TI stellt solche Chips beispielsweise routinemäßig her .quelle
Zitiert aus http://en.wikipedia.org/wiki/Byte#History
Ich bin mir jedoch nicht sicher über andere Sprachen.
http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats
Definiert ein Byte auf diesem Computer mit variabler Länge
quelle
Die DEC PDP-8-Familie hatte ein 12-Bit-Wort, obwohl Sie normalerweise 8-Bit-ASCII für die Ausgabe verwendeten (meistens auf einem Teletyp). Es gab jedoch auch einen 6-BIT-Zeichencode, mit dem Sie 2 Zeichen in einem einzelnen 12-Bit-Wort codieren konnten.
quelle
Zum einen sind Unicode-Zeichen länger als 8 Bit. Wie bereits erwähnt, definiert die C-Spezifikation Datentypen anhand ihrer Mindestgröße. Verwenden Sie
sizeof
und die Werte in,limits.h
wenn Sie Ihre Datentypen abfragen und genau herausfinden möchten, welche Größe sie für Ihre Konfiguration und Architektur haben.Aus diesem Grund versuche ich, mich an Datentypen zu halten, beispielsweise
uint16_t
wenn ich einen Datentyp mit einer bestimmten Bitlänge benötige.Edit: Sorry, ich habe deine Frage zunächst falsch verstanden.
Die C-Spezifikation besagt, dass ein
char
Objekt "groß genug ist, um ein Mitglied des Ausführungszeichensatzes zu speichern".limits.h
listet eine minimale Größe von 8 Bit auf, aber die Definition lässt die maximale Größe eineschar
offen.Somit ist das a
char
mindestens so lang wie das größte Zeichen aus dem Ausführungssatz Ihrer Architektur (normalerweise auf die nächste 8-Bit-Grenze aufgerundet). Wenn Ihre Architektur längere Opcodes enthält, ist Ihrechar
Größe möglicherweise länger.In der Vergangenheit war der Opcode der x86-Plattform ein Byte lang, also
char
zunächst ein 8-Bit-Wert. Aktuelle x86-Plattformen unterstützen Opcodes, die länger als ein Byte sind, aber diechar
Länge beträgt 8 Bit, da Programmierer (und die großen Mengen des vorhandenen x86-Codes) darauf konditioniert sind.Nutzen Sie die in definierten Typen, wenn Sie über die Unterstützung mehrerer Plattformen nachdenken
stdint.h
. Wenn Sie (zum Beispiel) ein uint16_t verwenden, dann können Sie sicher sein , dass dieser Wert ist ein unsigned 16-Bit - Wert aus welcher Architektur, ob die 16-Bit - Wert entspricht einenchar
,short
,int
, oder etwas anderes. Die meiste harte Arbeit wurde bereits von den Leuten geleistet, die Ihre Compiler- / Standardbibliotheken geschrieben haben.Wenn Sie die genaue Größe von a kennen müssen,
char
weil Sie eine Hardwaremanipulation auf niedriger Ebene durchführen, die dies erfordert, verwende ich normalerweise einen Datentyp, der groß genug ist, um achar
auf allen unterstützten Plattformen zu speichern (normalerweise sind 16 Bit ausreichend) und auszuführen der Wert durch eineconvert_to_machine_char
Routine, wenn ich die genaue Maschinendarstellung brauche. Auf diese Weise ist der plattformspezifische Code auf die Schnittstellenfunktion beschränkt und meistens kann ich einen normalen Code verwendenuint16_t
.quelle
magische Zahlen treten zB beim Verschieben auf;
Die meisten davon können ganz einfach mit CHAR_BIT und z. B. UCHAR_MAX anstelle von 8 und 255 (oder ähnlichem) behandelt werden.
hoffentlich definiert deine Implementierung diese :)
das sind die "gemeinsamen" Probleme .....
Ein weiteres indirektes Problem ist, dass Sie Folgendes haben:
Dies kann "nur" (im besten Fall) 24 Bit auf einer Plattform dauern, aber zB 72 Bit an anderer Stelle .....
Wenn jeder Uchar "Bit-Flags" enthielt und jeder Uchar nur 2 "signifikante" Bits oder Flags hatte, die Sie gerade verwendeten, und Sie sie aus "Klarheit" nur in 3 Uchars organisiert haben, ist dies möglicherweise relativ "verschwenderischer", z eine Plattform mit 24-Bit-Uchars .....
Nichts, was Bitfelder nicht lösen können, aber sie müssen auf andere Dinge achten ...
In diesem Fall kann nur eine einzige Aufzählung eine Möglichkeit sein, die "kleinste" Ganzzahl zu erhalten, die Sie tatsächlich benötigen.
vielleicht kein wirkliches Beispiel, aber solche Sachen "haben" mich beim Portieren / Spielen mit Code "gebissen" .....
Nur die Tatsache, dass, wenn ein Uchar dreimal so groß ist wie "normalerweise" erwartet, 100 solcher Strukturen auf einigen Plattformen viel Speicher verschwenden könnten ... wo "normalerweise" keine große Sache ist ... .
Daher können die Dinge immer noch "kaputt" sein oder in diesem Fall "sehr schnell viel Speicher verschwenden", da angenommen wird, dass ein Ukar auf einer Plattform im Verhältnis zum verfügbaren RAM "nicht sehr verschwenderisch" ist als auf einer anderen Plattform ... ..
Das Problem könnte z. B. auch für Ints oder andere Typen auftreten, z. B. wenn Sie eine Struktur haben, die 15 Bit benötigt, also stecken Sie sie in ein Int, aber auf einer anderen Plattform ist ein Int 48 Bit oder was auch immer .... .
"normal" könnten Sie es in 2 Uchars aufteilen, aber zB mit einem 24-Bit-Uchar würden Sie nur einen brauchen .....
Eine Aufzählung könnte also eine bessere "generische" Lösung sein ...
hängt davon ab, wie Sie auf diese Bits zugreifen :)
Es kann also zu "Designfehlern" kommen, die ihren Kopf aufrichten ... selbst wenn der Code ungeachtet der Größe eines Ukar oder Uint immer noch einwandfrei funktioniert / läuft ...
Es gibt solche Dinge, auf die Sie achten müssen, obwohl Ihr Code keine "magischen Zahlen" enthält ...
hoffe das macht Sinn :)
quelle
enum
nach wahrscheinlich kleiner als bei anderen einheimischen Typen? Ist Ihnen bewusst, dass standardmäßig derselbe Speicher verwendet wird wieint
? "Sie haben eine Struktur, die 15 Bit benötigt, also stecken Sie sie in ein Int, aber auf einer anderen Plattform ist ein Int 48 Bit oder was auch immer ....." - also#include <cstdint>
machen Sie es zu einerint16_t
für die beste Chance, die Bitverwendung zu minimieren . Ich bin mir wirklich nicht sicher, was Sie unter all diesen Ellipsen gesagt haben.Ints waren früher 16 Bit (pdp11 usw.). Es war schwierig, auf 32-Bit-Architekturen umzusteigen. Die Leute werden besser: Kaum jemand geht davon aus, dass ein Zeiger mehr passt (stimmt das nicht?). Oder Datei-Offsets oder Zeitstempel oder ...
8-Bit-Zeichen sind bereits ein Anachronismus. Wir benötigen bereits 32 Bit, um alle Zeichensätze der Welt aufzunehmen.
quelle
char
ist jetzt in Unicode-Tagen etwas kurios. Ich kümmere mich mehr um 8-Bit-Einheiten (Oktette) beim Umgang mit Binärdaten, z. B. Dateispeicherung, Netzwerkkommunikation.uint8_t
ist nützlicher.