Wie konvertiert man Big Endian in Little Endian in C, ohne Bibliotheksfunktionen zu verwenden?

Lesezeit: 5 Minuten

Benutzeravatar von Alex Xander
Alexander Xander

Ich muss eine Funktion schreiben, um eine Big-Endian-Ganzzahl in eine Little-Endian-Ganzzahl in C umzuwandeln. Ich kann keine Bibliotheksfunktion verwenden. Wie würde ich das tun?

  • 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önnen inline und es erledigt automatisch die Arbeit für Sie.

    – Alexis Wilke

    9. Juli 2021 um 1:10 Uhr

Benutzeravatar von Sam Post
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 0xdeadbeefein 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 einzelne rol Anweisung. Und wenn 32-Bit-Konvertierung als geschrieben wird ((num & 0xff000000) >> 24) | ((num & 0x00ff0000) >> 8) | ((num & 0x0000ff00) << 8) | (num << 24)generiert derselbe Compiler eine einzelne bswap 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 die union { 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

Benutzeravatar von Amir Mgh
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

Benutzeravatar von chmike
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 Und int64_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 ist swap_int64 Rückkehr uint64_t? Sollte das nicht sein int64_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

  • Danke. 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

  • Der LL sind unnötig (u)swap_uint64() ähnlich wie ein L wird nicht benötigt (u)swap_uint32(). Der U wird nicht benötigt uswap_uint64() ähnlich wie die U wird nicht benötigt uswap_uint32()

    – chux – Wiedereinsetzung von Monica

    2. April 2018 um 13:10 Uhr

Benutzeravatar von Michael J
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

Benutzeravatar von dreamlax
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

1447550cookie-checkWie konvertiert man Big Endian in Little Endian in C, ohne Bibliotheksfunktionen zu verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy