mikrocontroller.net

Forum: Compiler & IDEs Big Endian 2 little Endian


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Ach du dicker Vater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebes Forum, wie kann ich uint32_t Big Endian nach little Endian 
konvertieren? Meine Lösung hat jede Menge Schiebereien und Masken. Ich 
schäme mich dafür. Gibt es keine elegante Lösung?

Autor: Musl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: zitter_ned_aso (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

    uint32_t num=0x1f2f3f4f;
    printf("Zahl: %" PRIx32 "\n\n", num);

    const size_t ARR_LEN=sizeof(num);

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

    puts("");

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

Zahl: 1f2f3f4f

4f  3f  2f  1f  
1f  2f  3f  4f  

Autor: Andreas R. (daybyter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Niklas Gürtler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bit Shifts sind hier schon richtig. Deren Funktionsweise ist, im 
Gegensatz zu Pointer Spielchen und "union", garantiert. Siehe auch 
Serialisierung.

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach du dicker Vater schrieb:
> Meine Lösung hat jede Menge Schiebereien und Masken. Ich
> schäme mich dafür. Gibt es keine elegante Lösung?

Schreib es so hin, dass es leicht zu lesen ist.

Wenn der Compiler optimieren darf, wird er das erkennen.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

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

Mit GCC: __builtin_bswap32 (var)

Autor: NichtWichtig (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Hier gib es auch noch Lesestoiff, Lösungen und Beispiele

https://linux.die.net/man/3/endian

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Ach du dicker Vater schrieb:
>> wie kann ich uint32_t Big Endian nach little Endian konvertieren?
>
> Mit GCC: __builtin_bswap32 (var)

Viel zu einfach/funktionierend!

;-)

Autor: marais (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mach's so (vor Ewigkeiten irgendwo gefunden):
#define SWAP16(x) { register UINT8 aux8;     \
        aux8 = (UINT8) ((x) >> 8);           \
        (x) = ((x) << 8) | aux8; }

#define SWAP32(x) { register UINT32 aux32;   \
        aux32 = (x);                         \
        (x) = (aux32 >> 24 & 0xFF) | (aux32 >> 8 & 0xFF00); \
        (x)|= (aux32 << 24 & 0xFF000000) | (aux32 << 8 & 0xFF0000);}

Autor: my2ct (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
my2ct schrieb:
> Für zwei Vertauschungsoperationen von je zwei Bytes klingt "jede Menge
> Schiebereien und Masken" nicht nach dem direktesten Weg.

Naja, pro Byte einmal schieben und maskieren halt. Daher ja meine Frage, 
was der "dicke Vater" unter "jede Menge" versteht.

Autor: Markus F. (mfro)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
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).

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Rolf M. schrieb:
>> Naja, pro Byte einmal schieben und maskieren halt.
>
> Das muß am Ende nicht unbedingt das Ergebnis sein.

Es ging hier darum, wie der Code aussieht, nicht darum, was nachher der 
Compiler draus macht.

Autor: MikeH (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Für eine portable Lösung sollte man die Funktionen aus <netinet/in.h> 
verwenden. Andernfalls handelt man sich Ärger ein, wenn das Programm mal 
auf einer Bigendian Architektur übersetzt wird.

https://beej.us/guide/bgnet/html/multi/htonsman.html

Autor: PostalDude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"• 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.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PostalDude schrieb:
> #asm(" REV r0,r0");
> #asm(" bx lr");
>
> Und aus die Maus.

Und für welche Prozessor-Architektur gilt das überhaupt?

Autor: Niklas Gürtler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MikeH schrieb:
> Für eine portable Lösung sollte man die Funktionen aus <netinet/in.h>
> verwenden

Auch nicht so richtig portabel, da nur bei POSIX vorhanden. Bitweise 
Operationen hingegen gibt es immer.

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Und für welche Prozessor-Architektur gilt das überhaupt?

Ziemlich sicher ARM.
Aber #asm("bx lr") ist so ziemlich das dümmste, was man machen kann.

Die sinnvollste Lösung ist wahrscheinlich das genannte Compiler-Builtin, 
denn das ist garantiert optimal implementiert.

Autor: Mike (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Unbedingt mit den Funktionen: htons(), htonl(), ntohs(), ntohl()

=> wurde schon mal genannt.
https://beej.us/guide/bgnet/html/multi/htonsman.html

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

Autor: Niklas Gürtler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niklas Gürtler schrieb:
> Was ist der Vorteil gegenüber Bitshifts?

Und was ist der Nachteil gegenüber Bitshifts:

auf einem Big-Endian System machen diese Funktionen genau nullkommanix.

Wenn man das haben will (network byte order): gut. Wenn nicht, halt eher 
nicht...

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Niklas Gürtler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.:
uint16_t parse (const uint8_t* data, size_t length) {
  assert (length >= 2);
  return data [0] | (((uint16_t) data [1]) << 8);
}
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.

Autor: Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

: Bearbeitet durch User
Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.