Die bytes eines Integer bekommen
-
skizzenhaft:
#include <algorithm> template <typename T> T convert_endianess(const T& to_convert) { const char* ret_val = reinterpret_cast<const char*>(to_convert); std::reverse(ret_val, ret_val+sizeof(T)); return ret_val; }bb
-
</Exit> schrieb:
also ich habe einen (short) Integer der in Little Endian codiert ist.
Was heißt denn das? Werde doch mal konkreter.
</Exit> schrieb:
Mein gelesener Integer ist jetzt in little Endian,
Du meinst, Du hast einen int angelegt, und da per memcpy oder fread (oder ähnliches) da direkt Daten rein geschrieben?
Warum sollte man das so machen? (Ich frage absichtlich so "blöd")
</Exit> schrieb:
aber zum rechnen brauche ich Big Endian => konvertieren
Aha. Programmiere doch einfach plattformunabhängig, zB so:
#include <climits> #if CHAR_BIT != 8 #error "Ich kann nur mit 8-Bit Bytes. Wenigstens das bitte!" #endif #if UINT_MAX < 0xFFFFFFFF typedef unsigned long u32least; // mindestens 32 bit #else typedef unsigned int u32least; // mindestens 32 bit #endif inline u32least read_32le(unsigned char const* data) { return u32least(data[0]) | (u32least(data[1]) << 8u) | (u32least(data[2]) << 16u) | (u32least(data[3]) << 24u); }</Exit> schrieb:
Damit ich den Integer konvertieren kann, brauche ich allerdings Zugriff auf die einzelnen BYTES (den ich normalerweise bei einem Integer nicht habe)
Ja nee... brauchst Du eigentlich nicht.
-
"Warum sollte man das so machen?"
weil ein int in der Datei steht und ich später (nach dem Konvertieren) wieder einen int braucht, deshalb hab ich's in einen int gelesen...
Und den int will ich später vllt wieder in das Format zurückkonvertieren (und in die Datei zurückschreiben/in eine neue Datei schreiben), also brauch ich irgendwie Zugriff auf die einzelnen Bytes. Nur geht's irgendwie nicht
read_32le(unsigned char const* data)
und woher bekommst du den char*, wenn die Zeile char* = int* vom Compiler nicht akzeptiert wird?
-
Wenn Du an die Bytes eines int kommen möchtest, würde ich es mit Schieben machen.
int i = 0x12345678; unsigned char b0 = (unsigned char)i; unsigned char b1 = (unsigned char)(i>>8); unsigned char b2 = (unsigned char)(i>>16); unsigned char b3 = (unsigned char)(i>>24);Das ist immer plattformunabhängig. Du musst nicht auf Endianess achten.
Obiges Beispiel gilt für 4Bytes-Integer.
-
</Exit> schrieb:
"Warum sollte man das so machen?"
weil ein int in der Datei steht und ich später (nach dem Konvertieren) wieder einen int braucht, deshalb hab ich's in einen int gelesen...Ist klar, dass Du so gedacht hast. Ich wollte Dich anstoßen, genau das zu hinterfragen. Hat bisher leider nicht geklappt. Nein, Du musst die Daten nicht in einen
intlesen. Größe und Speicherlayout einesints sind ja nicht vorgeschrieben. Du musst Dich gar nicht mit diesen Eigenschaften der Implementierung auseinander setzen. Es steht auch kein "int in der Datei", sondern eine Folge aus Bytes. Wenn es sich um ein plattformunabhängiges Dateiformat handelt, ist auch festgelegt, was welches einzelne Byte zu bedeuten hat. Dann ist auch klar, wie man sich aus einzelnen Bytes den richtigen Wert ausrechnen kann ...</Exit> schrieb:
Und den int will ich später vllt wieder in das Format zurückkonvertieren (und in die Datei zurückschreiben/in eine neue Datei schreiben), also brauch ich irgendwie Zugriff auf die einzelnen Bytes.
Nein, brauchst Du nicht. Du kannst es auch über die Bit-Operatoren (<< >>, |, &) erledigen. Wenn Du keinen guten Grund dagegen hast, solltest Du das auch so machen. Später, wenn Du merkst, dass dieser Teil deines Programms einen Flaschenhals bzgl Performance darstellt (unwahrscheinlich), kannst Du probieren, ob eine speziell für Deine Big-Endian-Maschine geschriebene Funktion besser funktioniert. ZB so etwas wie:
inline u32least read_32le(unsigned char const* data) { u32least result; unsigned char* type_punning = reinterpret_cast<unsigned char*>(&result); for (int k=0; k<4; ++k) type_punning[3-k] = data[k]; return result; }Hier sagst Du dem Compiler per type punning, dass Du es besser weißt. Das ist dann aber auch nicht mehr plattformunabhängig. Ob das wirklich schneller ist, müsstest Du testen. Ich gehe nicht davon aus. Das wäre dann also eine ziemlich blöde Idee. --> Nimm erstmal die plattformunabhängige Version.
</Exit> schrieb:
u32least read_32le(unsigned char const* data);
und woher bekommst du den char*,Du lädst die Daten in einen unsigned char Puffer -- wie sich das gehört.
-
Eine wirklich unabhängige Variante bietet doch die von unskilled.
Sie ist weder abhängig von CHAR_BIT == 8 noch von der Größe des ints
-
gfzhjd schrieb:
Eine wirklich unabhängige Variante bietet doch die von unskilled.
Sie ist weder abhängig von CHAR_BIT == 8 noch von der Größe des intsAbgesehen davon, dass der Code falsch ist, hat unskilled eine Funktion bereit stellen wollen, die alle Bytes umdreht. Ob ein Aufruf dieser Funktion nötig ist oder nicht, ist plattformabhängig --> nicht "wirklich unabhängig".
Die Einschränkung auf CHAR_BIT==8 ist nicht wirklich eine Einschränkung. CHAR_BIT != 8 sollte höchst selten vorkommen. Und wenn Du doch versuchst, den Code auf einem DSP mit 16-Bit-Bytes oder einer PDP-11 mit 9-Bit-Bytes zu kompilieren, dann gibt's wenigstens eine Fehlermeldung wegen der #error-Zeile. Auf solchen Maschinen müsstest Du sowieso die Datei Ein/Ausgabe anpassen, wenn Dein Dateiformat über Oktetts definiert wurde. Die PDP-11 ist so exotisch, dass Du wahrscheinlich nicht mal so ohne weiteres die Datei eines 8-Bit-Bytes-basierten Dateiformates auf die PDP-11 übertragen bekommt... K.A. --- kenne mich mit sowas nicht aus.
-
Du meinst falsch wegen dem const?
template <typename T> //geändert T convert_endianess(T& to_convert) { unsigned char* ret_val = reinterpret_cast<unsigned char*>(&to_convert); std::reverse(ret_val, ret_val+sizeof(T)); return to_convert; }
-
wow, super danke für die zahlreichen Antworten!
Nachdem das nicht so einfach scheint, werde ich vllt doch als char einlesen und dann so shiften, dass der konvertierte int rauskommt.
Den reinterpret_cast find ich nicht sehr schön, außerdem hör ich ständig, dass man sowas nicht benutzen sollte...Bleibt nur noch die Frage wie ich den int wieder zurück bekomme?
Und kann ich das mit shiften eigentlich auch lösen, wenn ich nicht weiß ob der int 4 byte hat? (bei lesen weiß ich's, aber beim schreiben ja nicht!)
(ist ja nicht vorgeschrieben, wie groß der int ist...)thx...
-
</Exit> schrieb:
Nachdem das nicht so einfach scheint,
Mit "einfach" hat das nichts zu tun. Es ist super einfach, die Bytes (falls es mehrere sind) eines
ints zu vertauschen. Nur ist das nicht wirklich das, was Du tun solltest.</Exit> schrieb:
Den reinterpret_cast find ich nicht sehr schön, außerdem hör ich ständig, dass man sowas nicht benutzen sollte...

</Exit> schrieb:
Bleibt nur noch die Frage wie ich den int wieder zurück bekomme?
inline void write_32le(u32least value, unsigned char* out) { out[0] = (unsigned char) value; out[1] = (unsigned char)(value >> 8); out[2] = (unsigned char)(value >> 16); out[3] = (unsigned char)(value >> 24); }</Exit> schrieb:
Und kann ich das mit shiften eigentlich auch lösen, wenn ich nicht weiß ob der int 4 byte hat? (bei lesen weiß ich's, aber beim schreiben ja nicht!)
(ist ja nicht vorgeschrieben, wie groß der int ist...)*seufz*
Denk da nochmal drüber nach, was Du willst. Wie Du aus einer mehrbittigen Zahl eine Bytefolge bestimmst, die abgespeichert werden soll, hängt doch wohl von dem Dateiformat ab. Das Wegschreiben ist doch genau das Gegenstück zum Lesen. Warum soll das anders sein? Und wenn Du Zahlen lesen/schreiben können willst, die mehr Bits für die Darstellung benötigen als das, wasintbietet, dann nimmst Du eben long. Guck Dir dazu nochmal an, wie ich zumtypedeffüru32leastgekommen bin. Das ist der Typ, den Du nutzen solltest, wenn Du vorzeichelose Ganzzahlen mit mindestens 32 Bit benötigst .... nichtint. Ein int ist nur mindestens 16 Bit groß, siehe Integer Types in C and C++.
-
Den reinterpret_cast find ich nicht sehr schön, außerdem hör ich ständig, dass man sowas nicht benutzen sollte...Der schönste Cast von allen!
Der Compiler hält die Klappe und macht einfach
-
</Exit> schrieb:
Den reinterpret_cast find ich nicht sehr schön, außerdem hör ich ständig, dass man sowas nicht benutzen sollte...
Der reinterpret_cast sieht nicht schön aus, richtig. Und das soll er auch nicht, schließlich ist das was du da machst nichts gewöhnliches sondern eine absichliche Frickelei die am Typsystem von C++ komplett vorbei geht. Damit ist die rote Flagge, die durch das unschöne aussehn gesetzt wird, völlig berechigt und auch gut so, damits niemand einfach überlesen kann.
Und man sollte es im Normalfall nciht benutzen. Es sei denn man begeht irgendwelche nichtportablen Frickeleien die am Typsystem von C++ vorbeigehn, da ist der Cast-Operator genau das richtige Instrument für.
-
ok, thx, jetzt dürfte alles klar sein

-
Übrigens soll nur niemand auf die Idee kommen, C- und Function-Style-Casts seien "schöner". Auch wenn sie im Code sehr unscheinbar auftreten, sind sie die unsichersten (da sie die Funktionalität von
static_cast,const_castundreinterpret_castvereinen).(unsigned char*)var; // C-Style unsigned char*(var); // Funktions-Style
-
unsigned char*(var); // Funktions-Styleist eine Deklaration, kein Cast.
-
Tatsächlich, vielen Dank für den Hinweis. Ich bin mir die Klammern bei Deklarationen nicht gewohnt.
Wie kann man eigentlich einen Funktionsstyle-Cast mit
unsigned char*als Zieltyp durchführen? Also ohnetypedef. Das Folgende ist doch ein C-Cast, oder?unsigned char* ptr = (unsigned char*)(var);Spielt zwar keine Rolle, aber würde mich an dieser Stelle noch interessieren. Das geht ja wegen des Sternchens nicht:
unsigned char* ptr = unsigned char*(var);
-
Nexus schrieb:
Tatsächlich, vielen Dank für den Hinweis. Ich bin mir die Klammern bei Deklarationen nicht gewohnt.
Wie kann man eigentlich einen Funktionsstyle-Cast mit
unsigned char*als Zieltyp durchführen? Also ohnetypedef.Kann man nicht. Ein solcher Cast benötigt immer einen einfachen Typbezeichner.
-
camper schrieb:
Kann man nicht. Ein solcher Cast benötigt immer einen einfachen Typbezeichner.
Okay, danke vielmals.
Ich sehe immer wieder, dass es in eigentlich grundlegenden Gebieten von C++ Dinge gibt, welche ich nicht im Detail kenne (hier zum Beispiel, weil ich praktisch nie Function-Style-Casts einsetze). Irgendwie gefällt mir dieser Aspekt von C++.

-
Nexus schrieb:
Ich sehe immer wieder, dass es in eigentlich grundlegenden Gebieten von C++ Dinge gibt, welche ich nicht im Detail kenne ...
Ich denke auf konkrete Fragen kann niemand alle Details einfach aus dem Hut schütteln.
Man hat höchstens eine Ahnung und sieht dann im Standard nach (in diesem Fall §5.2.3). Würde mich schon schwer wundern, wenn jemand über 700 Seiten kryptische Definitionen auswendig könnte. Falls doch, kann er sonst nicht viele Aufgaben haben.
