Big Endian 2 little Endian

Gast
Ach du dicker Vater schrieb:
> uint32_t

Du kannst auch mit einem passenden Zeiger aus diesem 
4-Bytes-Speicherblock jedes Byte einzeln rauspicken und ausgeben/irgenwo 
ablegen.
1
    uint32_t num=0x1f2f3f4f;
2
    printf("Zahl: %" PRIx32 "\n\n", num);
3

4
    const size_t ARR_LEN=sizeof(num);
5

6
    for(size_t i=0; i<ARR_LEN; i++){
7
        printf("%" PRIx8 "\t", *((uint8_t*)&num+i));
8
    }
9

10
    puts("");
11

12
    for(size_t i=0; i<ARR_LEN; i++){
13
        printf("%" PRIx8 "\t", *((uint8_t*)&num+(ARR_LEN-1)-i));
14
    }
1
Zahl: 1f2f3f4f
2

3
4f  3f  2f  1f  
4
1f  2f  3f  4f
Ach du dicker Vater schrieb:
> Hallo liebes Forum, wie kann ich uint32_t Big Endian nach little Endian
> konvertieren? Meine Lösung hat jede Menge Schiebereien und Masken.

Kommt drauf an, was du unter "jede Menge" verstehst, aber klingt erstmal 
nicht falsch.

> Ich schäme mich dafür.

Warum?

> Gibt es keine elegante Lösung?

Was macht eine Lösung für dich elegant?
Gast
Ich mach's so (vor Ewigkeiten irgendwo gefunden):
1
#define SWAP16(x) { register UINT8 aux8;     \
2
        aux8 = (UINT8) ((x) >> 8);           \
3
        (x) = ((x) << 8) | aux8; }
4

5
#define SWAP32(x) { register UINT32 aux32;   \
6
        aux32 = (x);                         \
7
        (x) = (aux32 >> 24 & 0xFF) | (aux32 >> 8 & 0xFF00); \
8
        (x)|= (aux32 << 24 & 0xFF000000) | (aux32 << 8 & 0xFF0000);}
Gast
Rolf M. schrieb:
> Ach du dicker Vater schrieb:
>> Hallo liebes Forum, wie kann ich uint32_t Big Endian nach little Endian
>> konvertieren? Meine Lösung hat jede Menge Schiebereien und Masken.
>
> Kommt drauf an, was du unter "jede Menge" verstehst, aber klingt erstmal
> nicht falsch.

Für zwei Vertauschungsoperationen von je zwei Bytes klingt "jede Menge 
Schiebereien und Masken" nicht nach dem direktesten Weg.

Welche Wortbreite hat der Prozessor?
Rolf M. schrieb:
> Naja, pro Byte einmal schieben und maskieren halt.

Das muß am Ende nicht unbedingt das Ergebnis sein.

Compiler erkennen z.B., wenn rotiert werden soll. Auch wenn's in C kein 
Statement gibt, um diesen Wunsch direkt hinzuschreiben, wird - so denn 
die Plattform dafür einen Maschinenbefehl hat - im Code aus der 
Maskier-/Schieberei eine Rotate-Instruktion.

Compiler, die schlau genug sind, können genauso gut aus der 
entsprechenden Schiebe- und Maskierkombination eine BSWAP-Instruktion 
basteln (wenn es die auf der Zielplattform gibt).
Gast
"• REV: Converts either:
– 32-bit big-endian data into little-endian data
– or 32-bit little-endian data into big-endian data.
• REV16: Converts either:
– 16-bit big-endian data into little-endian data
– or 16-bit little-endian data into big-endian data.
• REVSH: Converts either:
– 16-bit signed big-endian data into 32-bit signed little-endian data
– 16-bit signed little-endian data into 32-bit signed big-endian data"


#asm(" REV r0,r0");
#asm(" bx lr");

Und aus die Maus.
Gast
Mike schrieb:
> Unbedingt mit den Funktionen: htons(), htonl(), ntohs(), ntohl()

Was ist der Vorteil gegenüber Bitshifts?

Mike schrieb:
> Die Funktionen machen nur was, wo nötig und je nach Compiler/Lib auch
> schön optimiert...

Bitshifts werden genau so vom Compiler optimiert. Außerdem gibt es die 
auch auf Nicht-Posix-Systemen.
Moderator
Mike schrieb:
> Unbedingt mit den Funktionen: htons(), htonl(), ntohs(), ntohl()

Ach du dicker Vater schrieb:
> wie kann ich uint32_t Big Endian nach little Endian konvertieren?

htonl() wäre dann richtig, wenn der TE geschrieben hätte:

  "wie kann ich uint32_t von der internen Darstellung nach der Network-
  Byte-Order konvertieren?"

Da die interne Darstellung nicht unbedingt Big-Endian und die Network-
Byte-Order nicht unbedingt Little-Endian sein muss, ist hier nach einer
Funktion gefragt, die die Byte-Reihenfolge auf jeden Fall umkehrt.
Gast
@Yalu X
>htonl() wäre dann richtig, wenn der TE geschrieben hätte:
>  wie kann ich uint32_t von der internen Darstellung nach der Network-
>  Byte-Order konvertieren?"

Ob der Host-Rechner (CPU) mit Big-Endian oder Little-Endian funzt, hängt 
von der Archidektur ab. Die Network-Byte-Order ist aber IMMER 
Big-Endian: Ergo mit dem 'htonl' Makro hat man unabhängig vom Host 
(portable) eine definierte Byteorder.
Gast
Mike schrieb:
> Die Network-Byte-Order ist aber IMMER
> Big-Endian: Ergo mit dem 'htonl' Makro hat man unabhängig vom Host
> (portable) eine definierte Byteorder.

Es gibt auch Netzwerk-Protokolle mit Little Endian, z.B. CANopen.

Mit Bitshifts kann man ganz genauso eine portable definierte Byte-Order 
erreichen, z.B.:
1
uint16_t parse (const uint8_t* data, size_t length) {
2
  assert (length >= 2);
3
  return data [0] | (((uint16_t) data [1]) << 8);
4
}
Gibt unabhängig von der Host-Order die ersten beiden Bytes des Puffers 
als Little Endian interpretiert zurück.

Allerdings war die Frage des TO überhaupt nicht, von einer bestimmten 
Reihenfolge auf die Host-Reihenfolge umzuwandeln, sondern lediglich, die 
Reihenfolge unabhängig vom Host zu verdrehen.
(Firma: Schweigstill IT) Persönliche Seite
Niklas Gürtler schrieb:
> Es gibt auch Netzwerk-Protokolle mit Little Endian, z.B. CANopen.

Das mag zwar durchaus so sein, aber htonl usw. stammen aber definitiv 
aus dem POSIX-API. Und selbiges umfasst primär die IP-basierte 
Kommunikation auf UNIX-artigen Systemen.

Auch wenn es vermutlich eher zur Polumkehrung des Erdmagnetfeldes kommen 
mag als zur Änderung der Network Byte Order und somit zur Änderung des 
Verhaltens von htonl usw., finde ich es aber auch semantisch ungünstig, 
auf ein Netzwerk-API zu referenzieren, wenn es überhaupt nicht um die 
Kommunikation mittels dieses API geht. Leider betreibt der TE aber 
natürlich die heute übliche Salamitaktik und nennt nicht etwa den 
Kontext, in dem er die Änderung der Endianess durchführen will/muss.

Generell halte ich es aber aber schon für sehr sinnvoll, die Anpassung 
der Endianess einer Bibliotheksfunktion zu überlassen, für die es ggf. 
je nach Prozessorarchitektur optimierte Implementierungen gibt.
Moderator
Mike schrieb:
> @Yalu X
>>htonl() wäre dann richtig, wenn der TE geschrieben hätte:
>>  wie kann ich uint32_t von der internen Darstellung nach der Network-
>>  Byte-Order konvertieren?"
>
> Ob der Host-Rechner (CPU) mit Big-Endian oder Little-Endian funzt, hängt
> von der Archidektur ab.

Das ist schon klar.

Leider meldet sich der TE nicht mehr, um uns mitzuteilen, was er mit der
Konvertierung tatsächlich bezwecken möchte. So bleibt uns als einzige
Information, dass er ein uint32_t von Big-Endian nach Little-Endian
konvertieren möchte. Woher das zu konvertierende uint32_t kommt, und
wohin das konvertierte uint32_t geht, bleibt dabei völlig im Dunkeln.
Unter den gegebenen Umständen muss man davon ausgehen, dass der Input
immer Big-Endian und der Output immer Little-Endian ist. Deswegen
ist ein Byte-Swap (egal, auf welche Weise realisiert), der einzig
richtige Vorschlag.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.