web-dev-qa-db-de.com

Was ist die Endianität von Binärliteralen in C++ 14?

Ich habe versucht, mich umzusehen, konnte aber nicht viel über Binärliterale und Endianness herausfinden. Sind binäre Literale Little-Endian, Big-Endian oder etwas anderes (z. B. passend zur Zielplattform)?

Was ist beispielsweise der Dezimalwert von 0b0111? Ist es 7? Plattformspezifisch? Etwas anderes? Bearbeiten: Ich habe einen schlechten Wert von 7 gewählt, da er innerhalb eines Bytes dargestellt wird. Trotzdem ist die Frage ausreichend beantwortet.

Hintergrund: Grundsätzlich versuche ich herauszufinden, wie hoch der Wert der niedrigstwertigen Bits ist, und es schien mir ein guter Weg zu sein, ihn mit binären Literalen zu maskieren ... aber nur, wenn es eine Garantie für Endianness gibt.

40
Levi Morrison

Kurze Antwort: es gibt keine .

Lange Antwort: Endianness wird niemals direkt im Code angezeigt, es sei denn, Sie versuchen wirklich, es herauszuholen (z. B. Zeigertricks). 0b0111 ist 7, es sind die gleichen Regeln wie Hex, Schreiben

int i = 0xAA77;

bedeutet auf einigen Plattformen nicht 0x77AA, weil das absurd wäre. Wohin würden die zusätzlichen 0s mit 32-Bit-Ints gehen? Würden sie auf der Vorderseite gepolstert, dann änderte sich das Ganze zu 0x77AA0000, oder würden sie danach hinzugefügt? Ich habe keine Ahnung, was jemand erwarten würde, wenn das der Fall wäre.

Der Punkt ist, dass C++ keine Annahmen über die Endiananness der Maschine macht. Wenn Sie Code mit Primitiven und den darin enthaltenen Literalen schreiben, wird das Verhalten von Maschine zu Maschine gleich sein (es sei denn, Sie beginnen, das Typsystem zu umgehen.) Möglicherweise müssen Sie tun

So adressieren Sie Ihr Update: Die Nummer wird so geschrieben, wie Sie es schreiben. Die Bits werden nicht umgeordnet oder ähnliches, das höchstwertige Bit befindet sich links und das niedrigstwertige Bit rechts.


Es scheint hier ein Missverständnis darüber zu geben, was Endianness ist . Endianness bezieht sich darauf, wie Bytes im Speicher angeordnet sind und wie sie interpretiert werden müssen. Wenn ich Ihnen die Nummer "4172" gab und sagte: "Wenn dies viertausendeinhundertzweiundsiebzig ist, was ist das Ende?", Können Sie keine Antwort geben, da die Frage keinen Sinn ergibt. ( Einige behaupten, dass die größte Ziffer auf der linken Seite Big-Endian bedeutet, aber ohne Speicher adressiert die Frage der Endianität nicht oder nicht relevant ). Dies ist nur eine Zahl, es gibt keine zu interpretierenden Bytes, keine Speicheradressen. Unter der Annahme einer 4-Byte-Ganzzahldarstellung sind die dazugehörigen Bytes:

        low address ----> high address
Big endian:    00 00 10 4c
Little endian: 4c 10 00 00

angesichts der beiden, denen gesagt wurde: "Dies ist die interne Darstellung des Computers von 4172", können Sie feststellen, ob es sich um einen kleinen oder großen Endian handelt.

Betrachten Sie nun Ihr binäres Literal 0b0111. Diese 4 Bits repräsentieren eine Nybble und können als beides gespeichert werden

              low ---> high
Big endian:    00 00 00 07
Little endian: 07 00 00 00

Sie müssen sich jedoch nicht darum kümmern, da dies auch von der Hardware gehandhabt wird. Die Sprache schreibt vor, dass der Compiler von links nach rechts liest, das höchstwertige Bit das niedrigstwertige Bit

Bei Endianness geht es nicht um einzelne Bits . Angenommen, ein Byte ist 8 Bits, wenn ich Ihnen 0b00000111 übergebe und sage: "Ist das ein kleiner oder großer Endianer?" Wieder kann man es nicht sagen, weil man nur ein Byte hat. Endianness ordnet Bits nicht in einem Byte neu an, sondern bezieht sich auf die Neuanordnung ganzer Bytes (es sei denn, Sie haben natürlich Ein-Bit-Bytes).

Sie müssen sich nicht darum kümmern, was Ihr Computer intern verwendet. 0b0111 erspart Ihnen nur die Zeit, so etwas zu schreiben

unsigned int mask = 7 // only keep the lowest 3 bits

schriftlich

unsigned int mask = 0b0111;

Ohne zu kommentieren, die Bedeutung der Nummer zu erklären.

70
Ryan Haining

Alle ganzzahligen Literale, einschließlich binärer, werden auf dieselbe Weise interpretiert, wie wir normalerweise Zahlen lesen (die linke Ziffer ist am wichtigsten).

Der C++ - Standard garantiert die gleiche Interpretation von Literalen, ohne dass Sie sich mit der spezifischen Umgebung befassen müssen. Daher müssen Sie sich in diesem Zusammenhang nicht mit der Endianness beschäftigen.

Ihr Beispiel für 0b0111 ist immer gleich sieben.

Der C++ - Standard verwendet keine Endianness-Begriffe in Bezug auf Zahlenliterale. Es beschreibt lediglich, dass Literale eine konsistente Interpretation haben und dass die Interpretation die ist, die Sie erwarten würden.

C++ - Standard - Ganzzahlige Literale - 2.14.2 - Absatz 1

Ein ganzzahliges Literal ist eine Folge von Ziffern, die weder einen Punkt noch einen - Exponent-Teil enthält. Optional können einzelne Anführungszeichen getrennt werden, die Ignoriert werden, wenn der Wert bestimmt wird. Ein ganzzahliges Literal kann ein Präfix haben, das Seine Basis und ein Suffix angibt, das seinen Typ angibt. Die lexikalisch Erste Ziffer der Ziffernfolge ist die signifikanteste. Ein binäres Integer-Literal (.____.) (Basis zwei) beginnt mit 0b oder 0B und besteht aus Einer Folge von Binärziffern. Ein oktales Integer-Literal (Basis acht) Beginnt mit der Ziffer 0 und besteht aus einer Folge von Oktalstellen. Ein dezimales Integer-Literal (Basis zehn) beginnt mit einer anderen Ziffer als 0 und besteht aus einer Folge von Dezimalstellen. Eine hexadezimale Integerzahl (Basis sechzehn) beginnt mit 0x oder 0X und besteht aus einer Folge Aus Hexadezimalziffern, die die Dezimalziffern und die Buchstaben a bis f und A enthalten bis F mit Dezimalwerten von zehn bis fünfzehn. [Beispiel: Die Zahl zwölf kann als 12, 014, 0XC oder 0b1100 geschrieben werden. Die Literale 1048576, 1'048'576, 0X100000, 0x10'0000 und 0’004'000'000 haben alle denselben Wert. - Ende Beispiel]

Wikipedia beschreibt, was endian ist, und verwendet unser Zahlensystem als Beispiel, um big-endian zu verstehen.

Die Ausdrücke endian und endianness beziehen sich auf die Konvention, mit der Die Bytes interpretiert, die ein Datenwort bilden, wenn diese Bytes Im Computerspeicher gespeichert werden.

Big-Endian-Systeme speichern das höchstwertige Byte eines Words in der Kleinsten Adresse und das niedrigstwertige Byte wird in der Größten Adresse gespeichert (siehe auch Höchstwertiges Bit). . Little-Endian-Systeme Dagegen speichern das niedrigstwertige Byte in der kleinsten Adresse.

Ein Beispiel für endianness ist das Nachdenken darüber, wie eine Dezimalzahl In Platzwertnotation geschrieben und gelesen wird. Angenommen, ein Schreibsystem , Bei dem Zahlen von links nach rechts geschrieben werden, ist die Position ganz links Analog zu der kleinsten Adresse des verwendeten Speichers und die Position ganz rechts Die größte. Zum Beispiel wird die Zahl einhundertdreiundzwanzig 1 2 3 geschrieben, wobei die Hundertstelle am weitesten links steht. Jeder, der Diese Zahl liest, weiß auch, dass die äußerste linke Ziffer den größten Wert für Hat. Dies ist ein Beispiel für eine Big-Endian-Konvention, die im täglichen Leben Befolgt wird.

In diesem Zusammenhang betrachten wir eine Ziffer eines ganzzahligen Literals als "Byte eines Wortes" und das Wort als das Literal selbst. Außerdem wird davon ausgegangen, dass das am weitesten links stehende Zeichen in einem Literal die kleinste Adresse hat.

Mit dem Literal 1234 sind die Ziffern eins, zwei, drei und vier die "Bytes eines Wortes" und 1234 das "Wort". Mit dem Binärliteral 0b0111 sind die Ziffern Null, Eins, Eins und Eins die "Bytes eines Wortes", und das Wort ist 0111.

Diese Überlegung erlaubt uns, Endianness im Kontext der C++ - Sprache zu verstehen, und zeigt, dass ganzzahlige Literale "big endian" ähnlich sind.

39
Michael Gazonda

Ihnen fehlt die Unterscheidung zwischen Endianness, wie im Quellcode geschrieben, und Endianness, wie im Objektcode dargestellt. Die Antwort für jede Frage ist nicht überraschend: Quellcode-Literale sind bigendian, weil Menschen sie so lesen. In Objektcode werden sie geschrieben, aber das Ziel liest sie.

Da ein Byte per Definition die kleinste Einheit des Speicherzugriffs ist, glaube ich nicht, dass es möglich ist, einer internen Darstellung von Bits in einem Byte sogar eine Endianannschaft zuzuschreiben Überraschung) ist der Zugriff auf sie stückweise, und das Byte ist definitionsgemäß die kleinste zugreifbare Speichereinheit.

10
jthill

Die C/C++ - Sprachen kümmern sich nicht um die Endianness von Multi-Byte-Ganzzahlen. C/C++ - Compiler tun dies. Compiler analysieren Ihren Quellcode und generieren Maschinencode für die jeweilige Zielplattform. Der Compiler speichert im Allgemeinen ganzzahlige Literale auf dieselbe Weise wie er eine ganze Zahl speichert. so dass die Anweisungen der Ziel-CPU direkt das Lesen und Schreiben in den Speicher unterstützen.

Der Compiler kümmert sich um die Unterschiede zwischen den Zielplattformen, so dass dies nicht erforderlich ist.

Das einzige Mal, wenn Sie sich um Endianness Sorgen machen müssen, ist, wenn Sie binäre Werte mit anderen Systemen teilen, die eine andere Byte-Reihenfolge haben. Dann würden Sie die binären Daten Byte für Byte einlesen und die Bytes im Speicher in der richtigen Reihenfolge für den Befehl anordnen System, auf dem Ihr Code ausgeführt wird. 

7
Theron W Genaux

Ein Bild enthält manchmal mehr als tausend Wörter.

 source vs. memory endianness

3
Zoltan Tirinda

Endianness ist implementierungsdefiniert. Der Standard garantiert, dass jedes Objekt über eine Objektrepräsentation als Array aus char und unsigned char verfügt, mit denen Sie arbeiten können, indem Sie memcpy() oder memcmp() aufrufen. In C++ 17 ist es legal, reinterpret_cast einen Zeiger oder einen Verweis auf einen beliebigen Objekttyp (nicht einen Zeiger auf void, einen Zeiger auf eine Funktion oder nullptr) auf einen Zeiger auf char, unsigned char oder std::byte, die gültige Aliase sind beliebiger Objekttyp.

Was Menschen meinen, wenn sie von „Endianismus“ sprechen, ist die Reihenfolge der Bytes in dieser Objektdarstellung. Wenn Sie beispielsweise unsigned char int_bytes[sizeof(int)] = {1}; und int i; deklarieren, erhalten Sie memcpy( &i, int_bytes, sizeof(i)); 0x01, 0x01000000, 0x0100, 0x0100000000000000 oder etwas anderes? Die Antwort ist ja. Es gibt realistische Implementierungen, die jedes dieser Ergebnisse erzeugen, und sie entsprechen alle dem Standard. Der Grund dafür ist, dass der Compiler das native Format der CPU verwenden kann.

Dies tritt am häufigsten auf, wenn ein Programm Daten über das Internet senden oder empfangen muss, wobei alle Standards festlegen, dass Daten in Big-Endian-Reihenfolge auf einer Little-Endian-CPU wie dem x86 übertragen werden sollen. Einige Netzwerkbibliotheken geben daher an, ob bestimmte Argumente und Strukturfelder in der Host- oder Netzwerk-Byte-Reihenfolge gespeichert werden sollen.

Mit der Sprache können Sie sich selbst in den Fuß schießen, indem Sie die Bits einer Objektdarstellung willkürlich drehen, aber Sie erhalten möglicherweise eineTrap-Darstellung , die zu einem undefinierten Verhalten führen kann, wenn Sie sie später verwenden. (Dies könnte beispielsweise bedeuten, dass eine virtuelle Funktionstabelle umgeschrieben wird, um beliebigen Code einzufügen.) Der <type_traits>-Header verfügt über mehrere Vorlagen, um zu testen, ob mit einer Objektrepräsentation sicher gearbeitet werden kann. Mit memcpy( &dest, &src, sizeof(dest) ) können Sie ein Objekt über ein anderes Objekt desselben Typs kopieren, sofern dieser Typ is_trivially_copyable ist. Sie können eine Kopie in den korrekt ausgerichteten, nicht initialisierten Speicher erstellen, wenn es is_trivially_move_constructible ist. Sie können testen, ob zwei Objekte desselben Typs mit memcmp( &a, &b, sizeof(a) ) identisch sind und ein Objekt richtig hashieren, indem Sie eine Hash-Funktion auf die Bytes in ihrer Objektdarstellung anwenden, wenn der Typ has_unique_object_representations. Ein ganzer Typ hat keine Überfüllungsdarstellungen und so weiter. Wenn Sie jedoch Operationen an Objektdarstellungen vornehmen, bei denen es auf die Endianness-Angelegenheit ankommt, sagen Sie dem Compiler, dass Sie wissen, was Sie tun, und Ihr Code wird nicht portierbar sein.

Wie bereits erwähnt, werden binäre Literale mit der höchstwertigen Ziffer geschrieben, wie Dezimal-, Oktal- oder Hexadezimal-Literalen. Dies unterscheidet sich von Endianness und hat keinen Einfluss darauf, ob Sie ntohs() für die Portnummer von einem aus dem Internet eingelesenen TCP -Header aufrufen müssen.

0
Davislor