Ich muss eine Funktion schreiben, um Big Endian in Little Endian in C zu konvertieren. Ich kann keine Bibliotheksfunktion verwenden.
Konvertieren Sie Big Endian in Little Endian in C [without using provided func] [closed]
Alexander Xander
Sam Post
Angenommen, Sie benötigen einen einfachen Byte-Swap, versuchen Sie so etwas wie
Vorzeichenlose 16-Bit-Konvertierung:
swapped = (num>>8) | (num<<8);
Vorzeichenlose 32-Bit-Konvertierung:
swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
((num<<8)&0xff0000) | // move byte 1 to byte 2
((num>>8)&0xff00) | // move byte 2 to byte 1
((num<<24)&0xff000000); // byte 0 to byte 3
Dadurch werden die Byte-Reihenfolgen von den Positionen 1234 bis 4321 vertauscht. Wenn Ihre Eingabe war 0xdeadbeef
ein 32-Bit-Endian-Swap könnte Ausgabe von haben 0xefbeadde
.
Der obige Code sollte mit Makros oder zumindest Konstanten anstelle von magischen Zahlen aufgeräumt werden, aber hoffentlich hilft es so wie es ist
BEARBEITEN: Wie eine andere Antwort hervorhob, gibt es plattform-, betriebssystem- und befehlssatzspezifische Alternativen, die VIEL schneller sein können als die oben genannten. Im Linux-Kernel gibt es Makros (zum Beispiel cpu_to_be32), die ziemlich gut mit Endianness umgehen. Aber diese Alternativen sind spezifisch für ihre Umgebung. In der Praxis wird Endianness am besten mit einer Mischung verfügbarer Ansätze behandelt
-
+1 für die Erwähnung plattform-/hardwarespezifischer Methoden. Programme werden immer auf einer bestimmten Hardware ausgeführt, und Hardwarefunktionen sind immer am schnellsten.
– Äonil
31. Juli 2012 um 6:47 Uhr
-
wenn die 16 bit wandlung so gemacht wird
((num & 0xff) >> 8) | (num << 8)
gcc 4.8.3 generiert eine einzelnerol
Anweisung. Und wenn 32-Bit-Konvertierung als geschrieben wird((num & 0xff000000) >> 24) | ((num & 0x00ff0000) >> 8) | ((num & 0x0000ff00) << 8) | (num << 24)
generiert derselbe Compiler eine einzelnebswap
Anweisung.– Benutzer666412
30. April 2015 um 16:51 Uhr
-
Ich weiß nicht, wie effizient das ist, aber ich habe die Byte-Reihenfolge mit Bitfeldern wie folgt ausgetauscht:
struct byte_t reverse(struct byte_t b) { struct byte_t rev; rev.ba = b.bh; rev.bb = b.bg; rev.bc = b.bf; rev.bd = b.be; rev.be = b.bd; rev.bf = b.bc; rev.bg = b.bb; rev.bh = b.ba; return rev;}
wobei dies ein Bitfeld mit 8 Feldern zu je 1 Bit ist. Aber ich bin mir nicht sicher, ob das so schnell ist wie die anderen Vorschläge. Verwenden Sie für Ints dieunion { int i; byte_t[sizeof(int)]; }
um Byte für Byte in der Ganzzahl umzukehren.– Iljan Saprjanow
26. September 2016 um 22:47 Uhr
-
Ich denke, der Ausdruck muss sein: (num >> 8) | (num << 8) um die Bytereihenfolge umzukehren und NICHT: ((num & 0xff) >> 8) | (num << 8), Das falsche Beispiel bekommt eine Null im Low-Byte.
– jscom
24. Februar 2017 um 17:14 Uhr
-
@IlianZapryanov Vielleicht +1 zur Verdeutlichung, aber die Verwendung solcher Bitfelder in C ist wahrscheinlich der am wenigsten effiziente Weg, dies zu tun.
– sherrelbc
26. September 2019 um 22:47 Uhr
Amir Mgh
Durch Einbeziehung:
#include <byteswap.h>
Sie können eine optimierte Version von maschinenabhängigen Byte-Swapping-Funktionen erhalten. Dann können Sie ganz einfach die folgenden Funktionen verwenden:
__bswap_32 (uint32_t input)
oder
__bswap_16 (uint16_t input)
-
Vielen Dank für Ihre Antwort, aber ich kann keine Bibliotheksfunktion verwenden
– Markieren Sie Lösegeld
5. August 2011 um 19:03 Uhr
-
Sollte lesen
#include <byteswap.h>
, siehe Kommentar in der .h-Datei selbst. Dieser Beitrag enthält hilfreiche Informationen, daher habe ich positiv gestimmt, obwohl der Autor die OP-Anforderung ignoriert hat, keine lib-Funktion zu verwenden.– Eli Rosencruft
20. Mai 2012 um 12:48 Uhr
-
Tatsächlich sind die __bswap_32/__bswap_16-Funktionen tatsächlich Makros und keine Bibliotheksfunktionen, ein weiterer Grund für eine positive Bewertung.
– Eli Rosencruft
20. Mai 2012 um 13:56 Uhr
-
Mein Verständnis ist, dass dieser Header nicht garantiert für alle Betriebssysteme auf allen Architekturen vorhanden ist. Ich muss noch einen tragbaren Weg finden, um mit Endian-Problemen umzugehen.
– Eduard Falk
18. Februar 2013 um 23:04 Uhr
-
#include <byteswap.h>
ist nicht Teil der C-Standardbibliothek.– chux – Wiedereinsetzung von Monica
2. April 2018 um 13:39 Uhr
chmike
#include <stdint.h>
//! Byte swap unsigned short
uint16_t swap_uint16( uint16_t val )
{
return (val << 8) | (val >> 8 );
}
//! Byte swap short
int16_t swap_int16( int16_t val )
{
return (val << 8) | ((val >> 8) & 0xFF);
}
//! Byte swap unsigned int
uint32_t swap_uint32( uint32_t val )
{
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
//! Byte swap int
int32_t swap_int32( int32_t val )
{
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF );
return (val << 16) | ((val >> 16) & 0xFFFF);
}
Aktualisieren : 64-Bit-Byte-Swapping hinzugefügt
int64_t swap_int64( int64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL);
}
uint64_t swap_uint64( uint64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | (val >> 32);
}
-
Für die
int32_t
undint64_t
Varianten, was ist der Grund für die Maskierung von... & 0xFFFF
und... & 0xFFFFFFFFULL
? Gibt es hier etwas mit der Zeichenerweiterung, das ich nicht sehe? Auch warum istswap_int64
Rückkehruint64_t
? Sollte das nicht seinint64_t
?– bgoodr
2. November 2012 um 14:57 Uhr
-
Der Swap_int64, der ein uint64 zurückgibt, ist in der Tat ein Fehler. Die Maskierung mit signierten int-Werten dient in der Tat dazu, das Vorzeichen zu entfernen. Eine Verschiebung nach rechts fügt das Vorzeichenbit auf der linken Seite ein. Wir könnten dies vermeiden, indem wir einfach die Operation unsigned int swapping aufrufen.
– Chike
3. November 2012 um 15:37 Uhr
-
Vielen Dank. Möglicherweise möchten Sie den Typ des Rückgabewerts für ändern
swap_int64
in deiner Antwort. +1 für die hilfreiche Antwort, übrigens!– bgoodr
4. November 2012 um 17:18 Uhr
-
Ist das bitweise und Wert-Endian abhängig?
– MarcusJ
4. Mai 2015 um 21:57 Uhr
-
Das
LL
sind unnötig(u)swap_uint64()
ähnlich wie einL
wird nicht benötigt(u)swap_uint32()
. DasU
wird nicht benötigtuswap_uint64()
ähnlich wie dieU
wird nicht benötigtuswap_uint32()
– chux – Wiedereinsetzung von Monica
2. April 2018 um 13:10 Uhr
Michael J
Hier ist eine ziemlich generische Version; Ich habe es nicht kompiliert, also gibt es wahrscheinlich Tippfehler, aber Sie sollten auf die Idee kommen,
void SwapBytes(void *pv, size_t n)
{
assert(n > 0);
char *p = pv;
size_t lo, hi;
for(lo=0, hi=n-1; hi>lo; lo++, hi--)
{
char tmp=p[lo];
p[lo] = p[hi];
p[hi] = tmp;
}
}
#define SWAP(x) SwapBytes(&x, sizeof(x));
Hinweis: Das ist nicht optimiert für Geschwindigkeit oder Platz. Es soll übersichtlich (einfach zu debuggen) und portabel sein.
Update 04.04.2018
Assert() hinzugefügt, um den ungültigen Fall von n == 0 abzufangen, wie vom Kommentator @chux entdeckt.
Wenn Sie Makros benötigen (z. B. eingebettetes System):
#define SWAP_UINT16(x) (((x) >> 8) | ((x) << 8))
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
-
Diese Makros sind in Ordnung, aber ((x) >> 24) schlägt fehl, wenn eine vorzeichenbehaftete Ganzzahl zwischen 0x80000000 und 0xffffffff liegt. Es ist eine gute Idee, hier bitweises UND zu verwenden. Hinweis: ((x) << 24) ist absolut sicher. (x) >> 8) schlägt auch fehl, wenn die hohen 16 Bits ungleich Null sind (oder ein vorzeichenbehafteter 16-Bit-Wert bereitgestellt wird).
– Benutzer1985657
19. November 2014 um 14:59 Uhr
-
@PacMan– Diese Makros sollen zum Austauschen verwendet werden ohne Vorzeichen nur ganze Zahlen. Deshalb gibt es die
UINT
in ihrem Namen.– Kol
19. November 2014 um 19:06 Uhr
-
Ja, stimmt, sorry für den Lärm. Wäre es nicht am besten, einen Typecast einzubetten?
– Benutzer1985657
19. November 2014 um 20:34 Uhr
Bearbeiten: Dies sind Bibliotheksfunktionen. Ihnen zu folgen ist der manuelle Weg, dies zu tun.
Ich bin absolut fassungslos über die Anzahl der Leute, die nichts davon wissen __byteswap_ushort, __byteswap_ulong und __byteswap_uint64. Sicher, sie sind Visual C++ spezifisch, aber sie werden auf x86/IA-64-Architekturen zu köstlichem Code kompiliert. 🙂
Hier ist eine explizite Verwendung der bswap
Anweisung, von dieser Seite gezogen. Beachten Sie, dass die obige intrinsische Form dies tut stets sei schneller als dasich habe es nur hinzugefügt, um eine Antwort ohne Bibliotheksroutine zu geben.
uint32 cq_ntohl(uint32 a) {
__asm{
mov eax, a;
bswap eax;
}
}
-
Diese Makros sind in Ordnung, aber ((x) >> 24) schlägt fehl, wenn eine vorzeichenbehaftete Ganzzahl zwischen 0x80000000 und 0xffffffff liegt. Es ist eine gute Idee, hier bitweises UND zu verwenden. Hinweis: ((x) << 24) ist absolut sicher. (x) >> 8) schlägt auch fehl, wenn die hohen 16 Bits ungleich Null sind (oder ein vorzeichenbehafteter 16-Bit-Wert bereitgestellt wird).
– Benutzer1985657
19. November 2014 um 14:59 Uhr
-
@PacMan– Diese Makros sollen zum Austauschen verwendet werden ohne Vorzeichen nur ganze Zahlen. Deshalb gibt es die
UINT
in ihrem Namen.– Kol
19. November 2014 um 19:06 Uhr
-
Ja, stimmt, sorry für den Lärm. Wäre es nicht am besten, einen Typecast einzubetten?
– Benutzer1985657
19. November 2014 um 20:34 Uhr
Traumlax
Als Witz:
#include <stdio.h>
int main (int argc, char *argv[])
{
size_t sizeofInt = sizeof (int);
int i;
union
{
int x;
char c[sizeof (int)];
} original, swapped;
original.x = 0x12345678;
for (i = 0; i < sizeofInt; i++)
swapped.c[sizeofInt - i - 1] = original.c[i];
fprintf (stderr, "%x\n", swapped.x);
return 0;
}
-
HAHAHAHA. Hahaha. Ha. Ha? (Welcher Witz?)
– Benutzer3139831
8. Januar 2015 um 13:58 Uhr
-
haben Sie dies aus einem Windows-Quellrepository gezogen? 🙂
– hochl
30. November 2016 um 14:24 Uhr
-
Nodejs verwendet diese Technik! github.com/nodejs/node/blob/…
– Justin Moser
25. März 2017 um 22:39 Uhr
-
Neugierig zu bedienen
int i, size_t sizeofInt
und nicht der gleiche Typ für beide.– chux – Wiedereinsetzung von Monica
2. April 2018 um 13:21 Uhr
ein 16-Bit-Wert? 32-Bit-Wert? schweben? eine Anordnung?
– Johannes Knöller
2. Februar 2010 um 5:54 Uhr
Zeit, vielleicht eine Antwort zu wählen?
– Aniket Inge
5. November 2012 um 9:02 Uhr
Abstimmung zur Wiedereröffnung. Identisch mit stackoverflow.com/questions/105252/… für C++. Wir könnten einfach bearbeiten, um das klarer zu machen.
– Ciro Santilli OurBigBook.com
8. April 2016 um 20:52 Uhr
Ich denke, es ist klar genug. Bitte öffnen Sie die Frage.
– Hamdi
20. Januar 2021 um 17:23 Uhr
gcc und g++ erkennen solche Swaps richtig und konvertieren sie in eine oder zwei Anweisungen, aber Sie müssen wahrscheinlich verwenden
-O3
oder zumindest-O2
. Sie sollten also eine einfache Funktion schreiben, mit der Sie den Austausch durchführen könneninline
und es erledigt automatisch die Arbeit für Sie.– Alexis Wilke
9. Juli 2021 um 1:10 Uhr