Big endian -> little endian
-
Hallo,
gibts ne Funktion für die Umwandlung eines Strings im Big Endian Format nach Little Endian ?
Gruß,
b.e.
-
Nein, denn Strings bestehen aus einer Aneinanderreihung einzelner Bytes. Byteordnung spielt für sie keine Rolle.
-
Wenn es sich um wchar_t Strings handelt, dann schon.
-
Du musst für jedes wchar_t Zeichen die Byte-Reihenfolge ändern (Bei 2 Byte einfach nur die Bytes tauschen(swappen)).
-
Und beachten, dass
wchar_t
nicht überall gleich groß sein muss.
-
Ich wusste doch, daß ich da was hab:
#ifndef UNION_ULU #define UNION_ULU union ULU // union for ip address { unsigned char c[4]; // hier: .c[3] = 0xde, .c[2] = 0xad, .c[1] = 0xbe, .c[0] = 0xef unsigned short s[2]; // big endian: .s[0] = 0xdead - hier: little endian: .s[0] = 0xbeef unsigned long l; // Eingabe: .l = 0xdeadbeef }; #endif // UNION_ULU ///:~
-
std::reverse?
-
issen1 schrieb:
std::reverse?
Nein!
-
nö++ schrieb:
issen1 schrieb:
std::reverse?
Nein!
wieso nicht? hatte sich jz nicht so verkehrt angehört...
bb
-
Irgendwie so vielleicht?
template<typename T> T endianSwap(T val) { unsigned char const * inPtr = reinterpret_cast<unsigned char const *>(&val); T swapped; unsigned char * swappedPtr = reinterpret_cast<unsigned char * >(&swapped); std::reverse_copy ( inPtr , inPtr + sizeof(val) , swappedPtr ); return swapped; }
-
Meine union ist doch (ausnahmsweise) gut kommentiert. Da sollte es doch klar sein wie's funktioniert.
Ich denke nicht, daß reverse funktioniert (hab aber keine Zeit, das jetzt zu testen).
Einfach nach deadbeef googlen.
-
big endianer schrieb:
Hallo,
gibts ne Funktion für die Umwandlung eines Strings im Big Endian Format nach Little Endian ?C++ kennt nicht "big endian" oder "little endian". Wie Objekte im Speicher liegen, ist Sache der Implementierung. Du solltest versuchen, all die Situationen zu vermeiden, welche Wissen über die Implementierung erfordern.
Übrigends: Unter Linux ist ein wchar_t 32Bit groß.
Übrigends: Es gibt auch Mischformen (mixed endian).@EOP:
Type-punning per union führt laut Standard zu undefiniertem Verhalten. Das, was Du da andeutest funktioniert nur bei bestimmten Compilern, die dies explizit als Erweiterung anbieten.Man kann aber auf PODs über einen char* oder unsigned char* zugreifen und per memcpy kopieren. Zum Beispiel so
wchar_t dings = 23; unsigned char* p = reinterpret_cast<unsigned char*>(&dings); std::reverse(p,p+sizeof(wchar_t));
Ob dabei aber etwas sinniges bei rumkommt, ist Implementierungssache.
Ich denke, das Problem kann und sollte man auch ohne diese "Hacks" lösen.
-
EOP schrieb:
Ich denke nicht, daß reverse funktioniert (hab aber keine Zeit, das jetzt zu testen).
Wieso sollte das nicht funktionieren?
-
Sebastian Pizer schrieb:
Ich denke, das Problem kann und sollte man auch ohne diese "Hacks" lösen.
Die Frage ist halt nur, wie? Wenn du etwas unbedingt als Little-Endian abspeichern musst und nicht weisst, wie die Repräsentation bei diesem Kompiler aussieht oder sogar klar ist, dass er Big-Endian verwendet, dann musst du entsprechende Konvertierungen vornehmen.
Für fundamentale Typen würde ich dazu wahrscheinlich Bitshifting nehmen, da die Repräsentation der Bits eindeutig definiert ist. Daher irgendetwas in dieser Art machen:
template<typename FundamentalT> void writeLittleEndian(FundamentalT fundamental, char* buffer, std::size_t size) { assert(buffer && size >= sizeof(fundamental)); // Oder zukünftig gleich static_assert? for(std::size_t b = 0; b < sizeof(fundamental); ++b, ++buffer) { char byte = static_cast<char>((fundamental >> (8 * b)) & 0xFF); *buffer = byte; } }
Ich hoffe, ich habe mich mit der Reihenfolge nicht vertan, ich verwechsle Big-Endian und Little-Endian immer wieder, keine Ahnung wieso
Aber das Prinzip sollte hier hoffentlich klar werden.Ich bin mir jetzt einzig grad nicht mehr sicher, wie es mit der Konvertierung nach char aussieht. Da gab es glaub ich noch irgendein Problem, was aber auf den meisten Kompiler keines ist, dafür nicht ganz Standardkonform ... Müsste ich zuerst nochmals nachschauen gehen.
Tachyon schrieb:
EOP schrieb:
Ich denke nicht, daß reverse funktioniert (hab aber keine Zeit, das jetzt zu testen).
Wieso sollte das nicht funktionieren?
Schon mal überlegt, was passiert, wenn man Little-Endian haben möchte und der Kompiler alles als Little-Endian darstellt? Oder womöglich sogar als ein Mixed-Endian?
Grüssli
-
Dravere schrieb:
Schon mal überlegt, was passiert, wenn man Little-Endian haben möchte und der Kompiler alles als Little-Endian darstellt? Oder womöglich sogar als ein Mixed-Endian?
GrüssliDer Name der Funktion ist schon Programm. Mehr als der Name sagt, tut die Funktion auch nicht...
Deine Lösung funktioniert nur für ordinale Typen, obwohl float/double auch fundamental sind.
Der Krams ist allerdings etwas zusammengestrichen aus Local-Net-Converts, die ich mal für etwas gebastelt habe. Die sehen dann so aus:
inline bool isBigEndian( ) { Byte bytes[2] = {0, 1}; return (reinterpret_cast<boost::uint16_t&>(*bytes) == 1); } template<typename T> inline void toNetConvert(T const & val, Byte * bytes) { //only fundamental types are convertible //even pure POD structs may cause alignment problems //so convert them element by element BOOST_STATIC_ASSERT(boost::is_fundamental<T>::value); //if the compilation stops here, the converted type //is non fundamental Byte const * inPtr = reinterpret_cast<Byte const*>(&val); if(isBigEndian()) { std::reverse_copy ( inPtr , inPtr + sizeof(val) , bytes ); } else { std::copy ( inPtr , inPtr + sizeof(val) , bytes ); } } template<typename T> inline void fromNetConvert(Byte const * bytes, T & val) { //only fundamental types are convertible //even pure POD structs may cause alignment problems //so convert them element by element BOOST_STATIC_ASSERT(boost::is_fundamental<T>::value); //if the compilation stops here, the converted type //is non fundamental if(isBigEndian()) { std::reverse_copy ( bytes , bytes + sizeof(val) , reinterpret_cast<Byte*>(&val) ); } else { std::copy ( bytes , bytes + sizeof(val) , reinterpret_cast<Byte*>(&val) ); } }
-
@Tachyon,
Ok, das ist aber nicht ausschliesslichstd::reverse
, sondern du machst zuerst eine Unterscheidung. Damit kann man es natürlich machen, wobei deine Lösung allerdings bei Middle(Mixed)-Endian auch nicht mehr funktioniert.Auch noch eine Möglichkeit gäbe es, dass man ein Muster anwendet. Das würde wohl auch für
float
,double
und auch für Middle-Endian Zeug funktionieren. Kurz ein wenig Code zur Erklärung:// Unter der Annahme assert(sizeof(int) == 4) int value = 234242; // Oder sonst ein Wert. unsigned int pattern = 0x00010203; char buffer[4]; char const* patternIndices = reinterpret_cast<char const*>(&pattern); char const* valueBuffer = reinterpret_cast<char const*>(&value); buffer[0] = valueBuffer[paternIndices[0]]; buffer[1] = valueBuffer[paternIndices[1]]; buffer[2] = valueBuffer[paternIndices[2]]; buffer[3] = valueBuffer[paternIndices[3]];
So ein Muster kann man sich auch je nach Typgrösse generieren lassen. Für
double
bräuchte man dann womöglich einenuint64_t
, was wieder nicht so ganz Standardkonform ist.Naja, die Sache ist eher mühsam
Grüssli
-
ZOMFG ist das alles dumm! Weil alle auch immer ihren eigenen rotzigen Weg gehen müssen!
Wie soll man sein Programm denn nun 100% portabel hinbekommen
Lauter Frickelcode den keiner versteht!