wake-up-neo.com

64 Bit ntohl () in C ++?

Die Manpages für htonl() scheinen darauf hinzudeuten, dass Sie sie nur für bis zu 32-Bit-Werte verwenden können. (In Wirklichkeit ist ntohl() für vorzeichenlose Länge definiert, was auf meiner Plattform 32 Bit entspricht. Ich nehme an, wenn die vorzeichenlose Länge 8 Byte wäre, würde dies für 64-Bit-Ints funktionieren.).

Mein Problem ist, dass ich 64-Bit-Ganzzahlen (in meinem Fall ist dies eine vorzeichenlose Long-Long-Zahl) von Big Endian in Little Endian konvertieren muss. Im Moment muss ich diese spezielle Konvertierung durchführen. Aber es wäre noch schöner, wenn die Funktion (wie ntohl()) meinen 64-Bit-Wert NICHT konvertieren würde, wenn die Zielplattform Big Endian wäre. (Ich würde es lieber vermeiden, meine eigene Präprozessor-Magie hinzuzufügen, um dies zu tun).

Was kann ich benutzen? Ich hätte gerne etwas, das Standard ist, wenn es existiert, aber ich bin offen für Implementierungsvorschläge. Ich habe diese Art der Umwandlung in der Vergangenheit mit Gewerkschaften gesehen. Ich nehme an, ich könnte eine Gewerkschaft mit einem unsignierten Long Long und einem Char [8] eingehen. Tauschen Sie dann die Bytes entsprechend aus. (Offensichtlich würde auf Plattformen, die Big Endian waren, brechen).

58
Tom

Dokumentation: man htobe64 unter Linux (glibc> = 2.9) oder FreeBSD.

Leider haben OpenBSD, FreeBSD und glibc (Linux) bei einem Versuch im Jahr 2009 nicht ganz reibungslos zusammengearbeitet, um einen (Nicht-Kernel-API) -Libc-Standard für diesen zu erstellen.

Derzeit ist dieses kurze Stück Präprozessor-Code:

#if defined(__linux__)
#  include <endian.h>
#Elif defined(__FreeBSD__) || defined(__NetBSD__)
#  include <sys/endian.h>
#Elif defined(__OpenBSD__)
#  include <sys/types.h>
#  define be16toh(x) betoh16(x)
#  define be32toh(x) betoh32(x)
#  define be64toh(x) betoh64(x)
#endif

(getestet unter Linux und OpenBSD) sollte die Unterschiede verbergen. Es gibt Ihnen die Linux/FreeBSD-ähnlichen Makros auf diesen 4 Plattformen.

Anwendungsbeispiel:

  #include <stdint.h>    // For 'uint64_t'

  uint64_t  Host_int = 123;
  uint64_t  big_endian;

  big_endian = htobe64( Host_int );
  Host_int = be64toh( big_endian );

Dies ist der derzeit gängigste Ansatz für C-Bibliotheken.

53

Ich würde empfehlen, dies zu lesen: http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

uint64_t
ntoh64(const uint64_t *input)
{
    uint64_t rval;
    uint8_t *data = (uint8_t *)&rval;

    data[0] = *input >> 56;
    data[1] = *input >> 48;
    data[2] = *input >> 40;
    data[3] = *input >> 32;
    data[4] = *input >> 24;
    data[5] = *input >> 16;
    data[6] = *input >> 8;
    data[7] = *input >> 0;

    return rval;
}

uint64_t
hton64(const uint64_t *input)
{
    return (ntoh64(input));
}

int
main(void)
{
    uint64_t ull;

    ull = 1;
    printf("%"PRIu64"\n", ull);

    ull = ntoh64(&ull);
    printf("%"PRIu64"\n", ull);

    ull = hton64(&ull);
    printf("%"PRIu64"\n", ull);

    return 0;
}

Zeigt die folgende Ausgabe an:

1
72057594037927936
1

Sie können dies mit ntohl () testen, wenn Sie die oberen 4 Bytes löschen.

Sie können dies auch in eine Nice-Template-Funktion in C++ umwandeln, die mit jeder Integer-Größe funktioniert:

template <typename T>
static inline T
hton_any(const T &input)
{
    T output(0);
    const std::size_t size = sizeof(input);
    uint8_t *data = reinterpret_cast<uint8_t *>(&output);

    for (std::size_t i = 0; i < size; i++) {
        data[i] = input >> ((size - i - 1) * 8);
    }

    return output;
}

Jetzt ist auch Ihr 128 Bit sicher!

17
user442585

Verwenden Sie die folgende Vereinigung, um Ihr Endian-ness zu ermitteln:

union {
    unsigned long long ull;
    char c[8];
} x;
x.ull = 0x0123456789abcdef; // may need special suffix for ULL.

Anschließend können Sie den Inhalt von x.c[] Überprüfen, um festzustellen, wohin die einzelnen Bytes verschoben wurden.

Um die Konvertierung durchzuführen, würde ich diesen Erkennungscode einmal verwenden, um zu sehen, welches Endian-ness die Plattform verwendet, und dann meine eigene Funktion schreiben, um die Auslagerungen durchzuführen.

Sie könnten es dynamisch machen, so dass der Code auf jeder Plattform ausgeführt wird (einmal erkennen und dann einen Schalter in Ihrem Conversion-Code verwenden, um die richtige Conversion auszuwählen). Wenn Sie jedoch nur eine Plattform verwenden, würde ich dies einfach tun Die Erkennung wird einmal in einem separaten Programm ausgeführt. Anschließend wird eine einfache Konvertierungsroutine codiert, um sicherzustellen, dass Sie dokumentieren, dass sie nur auf dieser Plattform ausgeführt wird (oder getestet wurde).

Hier ist ein Beispielcode, den ich zur Veranschaulichung zusammengestellt habe. Es wurde zwar nicht gründlich getestet, sollte aber ausreichen, um Ihnen den Einstieg zu erleichtern.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2

static unsigned long long cvt(unsigned long long src) {
    static int typ = TYP_INIT;
    unsigned char c;
    union {
        unsigned long long ull;
        unsigned char c[8];
    } x;

    if (typ == TYP_INIT) {
        x.ull = 0x01;
        typ = (x.c[7] == 0x01) ? TYP_BIGE : TYP_SMLE;
    }

    if (typ == TYP_SMLE)
        return src;

    x.ull = src;
    c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
    c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
    c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
    c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
    return x.ull;
}

int main (void) {
    unsigned long long ull = 1;
    ull = cvt (ull);
    printf ("%llu\n",ull);
    return 0;
}

Denken Sie daran, dass dies nur nach reinem Big/Little Endian sucht. Wenn Sie eine seltsame Variante haben, in der die Bytes beispielsweise in der Reihenfolge {5,2,3,1,0,7,6,4} gespeichert sind, ist cvt() etwas komplexer. Eine solche Architektur hat es nicht verdient zu existieren, aber ich schätze den Wahnsinn unserer Freunde in der Mikroprozessorindustrie nicht ein :-)

Denken Sie auch daran, dass dies ein technisch undefiniertes Verhalten ist, da Sie auf ein Gewerkschaftsmitglied nur über das zuletzt geschriebene Feld zugreifen dürfen. Es wird wahrscheinlich mit den meisten Implementierungen funktionieren, aber aus puristischer Sicht sollten Sie wahrscheinlich nur in die Kugel beißen und Makros verwenden, um Ihre eigenen Routinen zu definieren, wie zum Beispiel:

// Assumes 64-bit unsigned long long.
unsigned long long switchOrderFn (unsigned long long in) {
    in  = (in && 0xff00000000000000ULL) >> 56
        | (in && 0x00ff000000000000ULL) >> 40
        | (in && 0x0000ff0000000000ULL) >> 24
        | (in && 0x000000ff00000000ULL) >> 8
        | (in && 0x00000000ff000000ULL) << 8
        | (in && 0x0000000000ff0000ULL) << 24
        | (in && 0x000000000000ff00ULL) << 40
        | (in && 0x00000000000000ffULL) << 56;
    return in;
}
#ifdef ULONG_IS_NET_ORDER
    #define switchOrder(n) (n)
#else
    #define switchOrder(n) switchOrderFn(n)
#endif
14
paxdiablo

einige BSD-Systeme haben betoh64 was macht was du brauchst.

12
Francis

Schnelle Antwort

#include <endian.h>    // __BYTE_ORDER __LITTLE_ENDIAN
#include <byteswap.h>  // bswap_64()

uint64_t value = 0x1122334455667788;

#if __BYTE_ORDER == __LITTLE_ENDIAN
value = bswap_64(value);  // Compiler builtin GCC/Clang
#endif

Header-Datei

Wie von zhaorufei (siehe Kommentar) berichtet, ist endian.h Kein C++ - Standardheader und die Makros __BYTE_ORDER Und __LITTLE_ENDIAN Können undefiniert sein. Daher ist die Anweisung #if Nicht vorhersehbar, da nicht definierte Makros als 0 Behandelt werden.

Bearbeiten Sie diese Antwort, wenn Sie Ihren eleganten C++ - Trick zur Erkennung von Endianness teilen möchten.

Portabilität

Darüber hinaus ist das Makro bswap_64() für GCC- und Clang-Compiler verfügbar, nicht jedoch für Visual C++ - Compiler. Um einen portablen Quellcode bereitzustellen, können Sie sich von folgendem Snippet inspirieren lassen:

#ifdef _MSC_VER
  #include <stdlib.h>
  #define bswap_16(x) _byteswap_ushort(x)
  #define bswap_32(x) _byteswap_ulong(x)
  #define bswap_64(x) _byteswap_uint64(x)
#else
  #include <byteswap.h>  // bswap_16 bswap_32 bswap_64
#endif

Siehe auch einen portableren Quellcode: Plattformübergreifend _byteswap_uint64

C++ 14 constexpr Template-Funktion

Generisches hton() für 16 Bit, 32 Bit, 64 Bit und mehr ...

#include <endian.h>   // __BYTE_ORDER __LITTLE_ENDIAN
#include <algorithm>  // std::reverse()

template <typename T>
constexpr T htonT (T value) noexcept
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
  char* ptr = reinterpret_cast<char*>(&value);
  std::reverse(ptr, ptr + sizeof(T));
#endif
  return value;
}

C++ 11 constexpr Template-Funktion

  • In C++ 11 sind lokale Variablen in der Funktion constexpr nicht zulässig.
    Daher besteht der Trick darin, ein Argument mit Standardwert zu verwenden.
  • Darüber hinaus muss die C++ 11 constexpr -Funktion einen einzelnen Ausdruck enthalten.
    Daher besteht der Körper aus einem Return mit einigen durch Kommas getrennten Anweisungen.
template <typename T>
constexpr T htonT (T value, char* ptr=0) noexcept
{
  return 
#if __BYTE_ORDER == __LITTLE_ENDIAN
    ptr = reinterpret_cast<char*>(&value), 
    std::reverse(ptr, ptr + sizeof(T)),
#endif
    value;
}

Keine Kompilierungswarnung bei clang-3.5 und GCC-4.9 mit -Wall -Wextra -pedantic
(siehe Kompilierung und Ausgabe am colir ausführen).

C++ 11 constexpr Template-SFINAE-Funktionen

Die obige Version erlaubt jedoch nicht die Erstellung von constexpr Variablen als:

constexpr int32_t hton_six = htonT( int32_t(6) );

Schließlich müssen wir die Funktionen in Abhängigkeit von 16/32/64 Bits trennen (spezialisieren).
Aber wir können immer noch allgemeine Funktionen behalten.
(siehe den vollständigen Ausschnitt auf colir )

Das folgende C++ 11-Snippet verwendet Eigenschaftenstd::enable_if , um Substitutionsfehler sind kein Fehler (SFINAE) auszunutzen.

template <typename T>
constexpr typename std::enable_if<sizeof(T) == 2, T>::type
htonT (T value) noexcept
{
   return  ((value & 0x00FF) << 8)
         | ((value & 0xFF00) >> 8);
}

template <typename T>
constexpr typename std::enable_if<sizeof(T) == 4, T>::type
htonT (T value) noexcept
{
   return  ((value & 0x000000FF) << 24)
         | ((value & 0x0000FF00) <<  8)
         | ((value & 0x00FF0000) >>  8)
         | ((value & 0xFF000000) >> 24);
}

template <typename T>
constexpr typename std::enable_if<sizeof(T) == 8, T>::type
htonT (T value) noexcept
{
   return  ((value & 0xFF00000000000000ull) >> 56)
         | ((value & 0x00FF000000000000ull) >> 40)
         | ((value & 0x0000FF0000000000ull) >> 24)
         | ((value & 0x000000FF00000000ull) >>  8)
         | ((value & 0x00000000FF000000ull) <<  8)
         | ((value & 0x0000000000FF0000ull) << 24)
         | ((value & 0x000000000000FF00ull) << 40)
         | ((value & 0x00000000000000FFull) << 56);
}

Oder eine noch kürzere Version basierend auf eingebauten Compiler-Makros und C++ 14-Syntax std::enable_if_t<xxx> Als Abkürzung für std::enable_if<xxx>::type:

template <typename T>
constexpr typename std::enable_if_t<sizeof(T) == 2, T>
htonT (T value) noexcept
{
    return bswap_16(value);  // __bswap_constant_16
}

template <typename T>
constexpr typename std::enable_if_t<sizeof(T) == 4, T>
htonT (T value) noexcept
{
    return bswap_32(value);  // __bswap_constant_32
}

template <typename T>
constexpr typename std::enable_if_t<sizeof(T) == 8, T>
htonT (T value) noexcept
{
    return bswap_64(value);  // __bswap_constant_64
}

Testcode der ersten Version

std::uint8_t uc = 'B';                  std::cout <<std::setw(16)<< uc <<'\n';
uc = htonT( uc );                       std::cout <<std::setw(16)<< uc <<'\n';

std::uint16_t us = 0x1122;              std::cout <<std::setw(16)<< us <<'\n';
us = htonT( us );                       std::cout <<std::setw(16)<< us <<'\n';

std::uint32_t ul = 0x11223344;          std::cout <<std::setw(16)<< ul <<'\n';
ul = htonT( ul );                       std::cout <<std::setw(16)<< ul <<'\n';

std::uint64_t uL = 0x1122334455667788; std::cout <<std::setw(16)<< uL <<'\n';
uL = htonT( uL );                      std::cout <<std::setw(16)<< uL <<'\n';

Testcode der zweiten Version

constexpr uint8_t  a1 = 'B';               std::cout<<std::setw(16)<<a1<<'\n';
constexpr auto     b1 = htonT(a1);         std::cout<<std::setw(16)<<b1<<'\n';

constexpr uint16_t a2 = 0x1122;            std::cout<<std::setw(16)<<a2<<'\n';
constexpr auto     b2 = htonT(a2);         std::cout<<std::setw(16)<<b2<<'\n';

constexpr uint32_t a4 = 0x11223344;        std::cout<<std::setw(16)<<a4<<'\n';
constexpr auto     b4 = htonT(a4);         std::cout<<std::setw(16)<<b4<<'\n';

constexpr uint64_t a8 = 0x1122334455667788;std::cout<<std::setw(16)<<a8<<'\n';
constexpr auto     b8 = htonT(a8);         std::cout<<std::setw(16)<<b8<<'\n';

Ausgabe

               B
               B
            1122
            2211
        11223344
        44332211
1122334455667788
8877665544332211

Codegenerierung

Der Online-C++ - Compiler gcc.godbolt.org gibt den generierten Code an.

g++-4.9.2 -std=c++14 -O3

std::enable_if<(sizeof (unsigned char))==(1), unsigned char>::type htonT<unsigned char>(unsigned char):
    movl    %edi, %eax
    ret
std::enable_if<(sizeof (unsigned short))==(2), unsigned short>::type htonT<unsigned short>(unsigned short):
    movl    %edi, %eax
    rolw    $8, %ax
    ret
std::enable_if<(sizeof (unsigned int))==(4), unsigned int>::type htonT<unsigned int>(unsigned int):
    movl    %edi, %eax
    bswap   %eax
    ret
std::enable_if<(sizeof (unsigned long))==(8), unsigned long>::type htonT<unsigned long>(unsigned long):
    movq    %rdi, %rax
    bswap   %rax
    ret

clang++-3.5.1 -std=c++14 -O3

std::enable_if<(sizeof (unsigned char))==(1), unsigned char>::type htonT<unsigned char>(unsigned char): # @std::enable_if<(sizeof (unsigned char))==(1), unsigned char>::type htonT<unsigned char>(unsigned char)
    movl    %edi, %eax
    retq

std::enable_if<(sizeof (unsigned short))==(2), unsigned short>::type htonT<unsigned short>(unsigned short): # @std::enable_if<(sizeof (unsigned short))==(2), unsigned short>::type htonT<unsigned short>(unsigned short)
    rolw    $8, %di
    movzwl  %di, %eax
    retq

std::enable_if<(sizeof (unsigned int))==(4), unsigned int>::type htonT<unsigned int>(unsigned int): # @std::enable_if<(sizeof (unsigned int))==(4), unsigned int>::type htonT<unsigned int>(unsigned int)
    bswapl  %edi
    movl    %edi, %eax
    retq

std::enable_if<(sizeof (unsigned long))==(8), unsigned long>::type htonT<unsigned long>(unsigned long): # @std::enable_if<(sizeof (unsigned long))==(8), unsigned long>::type htonT<unsigned long>(unsigned long)
    bswapq  %rdi
    movq    %rdi, %rax
    retq

Hinweis: Mein rsprüngliche Antwort war nicht C++ 11 -constexpr-konform.

Diese Antwort ist in Public Domain CC0 1.0 Universal

11
olibre

einzeiliges Makro für 64-Bit-Swap auf Little-Endian-Rechnern.

#define bswap64(y) (((uint64_t)ntohl(y)) << 32 | ntohl(y>>32))
6
Sandeep
uint32_t SwapShort(uint16_t a)
{
  a = ((a & 0x00FF) << 8) | ((a & 0xFF00) >> 8);
  return a;
}

uint32_t SwapWord(uint32_t a)
{
  a = ((a & 0x000000FF) << 24) |
      ((a & 0x0000FF00) <<  8) |
      ((a & 0x00FF0000) >>  8) |
      ((a & 0xFF000000) >> 24);
  return a;
}

uint64_t SwapDWord(uint64_t a)
{
  a = ((a & 0x00000000000000FFULL) << 56) | 
      ((a & 0x000000000000FF00ULL) << 40) | 
      ((a & 0x0000000000FF0000ULL) << 24) | 
      ((a & 0x00000000FF000000ULL) <<  8) | 
      ((a & 0x000000FF00000000ULL) >>  8) | 
      ((a & 0x0000FF0000000000ULL) >> 24) | 
      ((a & 0x00FF000000000000ULL) >> 40) | 
      ((a & 0xFF00000000000000ULL) >> 56);
  return a;
}
5
kuzne4ik

Wie wäre es mit einer generischen Version, die nicht von der Eingabegröße abhängt (einige der obigen Implementierungen gehen davon aus, dass unsigned long long ist 64 Bit, was nicht immer der Fall sein muss):

    // converts an arbitrary large integer (preferrably >=64 bits) from big endian to Host machine endian
    template<typename T> static inline T bigen2Host(const T& x)
    {
        static const int one = 1;
        static const char sig = *(char*)&one; 

        if (sig == 0) return x; // for big endian machine just return the input

        T ret;
        int size = sizeof(T);
        char* src = (char*)&x + sizeof(T) - 1;
        char* dst = (char*)&ret;

        while (size-- > 0) *dst++ = *src--;

        return ret;
    }
5
Andrei Bozantan

Wie wäre es mit:

#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | 
    ntohl( ((uint32_t)(x >> 32)) ) )                                        
#define htonll(x) ntohll(x)
3
Matt

Ich mag die Gewerkschaftsantwort, ziemlich ordentlich. Normalerweise verschiebe ich mich nur ein bisschen, um zwischen Little- und Big-Endian zu konvertieren, obwohl ich denke, dass die Union-Lösung weniger Aufgaben hat und möglicherweise schneller ist:

//note UINT64_C_LITERAL is a macro that appends the correct prefix
//for the literal on that platform
inline void endianFlip(unsigned long long& Value)
{
   Value=
   ((Value &   UINT64_C_LITERAL(0x00000000000000FF)) << 56) |
   ((Value &   UINT64_C_LITERAL(0x000000000000FF00)) << 40) |
   ((Value &   UINT64_C_LITERAL(0x0000000000FF0000)) << 24) |
   ((Value &   UINT64_C_LITERAL(0x00000000FF000000)) << 8)  |
   ((Value &   UINT64_C_LITERAL(0x000000FF00000000)) >> 8)  | 
   ((Value &   UINT64_C_LITERAL(0x0000FF0000000000)) >> 24) |
   ((Value &   UINT64_C_LITERAL(0x00FF000000000000)) >> 40) |
   ((Value &   UINT64_C_LITERAL(0xFF00000000000000)) >> 56);
}

Um dann zu erkennen, ob Sie Ihren Flip auch ohne Makromagie ausführen müssen, können Sie eine ähnliche Aktion wie Pax ausführen. Wenn ein Short 0x0001 zugewiesen wird, lautet er auf dem gegenüberliegenden Endian-System 0x0100.

So:

unsigned long long numberToSystemEndian
(
    unsigned long long In, 
    unsigned short SourceEndian
)
{
   if (SourceEndian != 1)
   {
      //from an opposite endian system
      endianFlip(In);
   }
   return In;
}

Um dies zu verwenden, müsste SourceEndian ein Indikator sein, um die Endianität der Eingabenummer zu kommunizieren. Dies kann in der Datei gespeichert werden (wenn dies ein Serialisierungsproblem ist) oder über das Netzwerk kommuniziert werden (wenn es sich um ein Netzwerkserialisierungsproblem handelt).

2
Snazzer

Eine einfache Möglichkeit wäre, ntohl für beide Teile separat zu verwenden:

unsigned long long htonll(unsigned long long v) {
    union { unsigned long lv[2]; unsigned long long llv; } u;
    u.lv[0] = htonl(v >> 32);
    u.lv[1] = htonl(v & 0xFFFFFFFFULL);
    return u.llv;
}

unsigned long long ntohll(unsigned long long v) {
    union { unsigned long lv[2]; unsigned long long llv; } u;
    u.llv = v;
    return ((unsigned long long)ntohl(u.lv[0]) << 32) | (unsigned long long)ntohl(u.lv[1]);
}
2
bdonlan

htonl kann wie folgt ausgeführt werden

  • Wenn sein Big-Endian-System den Wert direkt zurückgibt. Es ist keine Konvertierung erforderlich. Wenn es ein kleines Endian-System ist, muss die folgende Konvertierung durchgeführt werden.
  • Nimm LSB 32 Bit und wende 'htonl' an und verschiebe 32 mal.
  • Nimm MSB 32 Bit (indem du den Wert von uint64_t 32 mal nach rechts verschiebst) und wende 'htonl' an
  • Wenden Sie nun bitweise OR für den im 2. und 3. Schritt empfangenen Wert an.

Ähnliches gilt für ntohll

#define HTONLL(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
#define NTOHLL(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))

Sie können über 2 Definitionen als Funktionen auch delcare.

1
rashok
template <typename T>
static T ntoh_any(T t)
{
    static const unsigned char int_bytes[sizeof(int)] = {0xFF};
    static const int msb_0xFF = 0xFF << (sizeof(int) - 1) * CHAR_BIT;
    static bool Host_is_big_endian = (*(reinterpret_cast<const int *>(int_bytes)) & msb_0xFF ) != 0;
    if (Host_is_big_endian) { return t; }

    unsigned char * ptr = reinterpret_cast<unsigned char *>(&t);
    std::reverse(ptr, ptr + sizeof(t) );
    return t;
}

Funktioniert für 2 Bytes, 4 Bytes, 8 Bytes und 16 Bytes (wenn Sie eine Ganzzahl von 128 Bits haben). Sollte OS/plattformunabhängig sein.

0
zhaorufei

universelle Funktion für jede Wertgröße.

template <typename T>
T swap_endian (T value)
{
    union {
        T src;
        unsigned char dst[sizeof(T)];
    } source, dest;

    source.src = value;
    for (size_t k = 0; k < sizeof(T); ++k)
        dest.dst[k] = source.dst[sizeof(T) - k - 1];

    return dest.src;
}
0
Виталий

Dies setzt voraus, dass Sie unter Linux mit 64-Bit-Betriebssystemen codieren. Die meisten Systeme haben htole(x) oder ntobe(x) usw., dies sind normalerweise Makros für die verschiedenen bswap

#include <endian.h>
#include <byteswap.h>

unsigned long long htonll(unsigned long long val)
{
    if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
    else return __bswap_64(val);
}

unsigned long long ntohll(unsigned long long val)
{
    if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
    else return __bswap_64(val);
}

Randnotiz; Dies sind nur Funktionen, die aufgerufen werden müssen, um die Bytereihenfolge zu vertauschen. Wenn Sie Little Endian zum Beispiel mit einem Big Endian-Netzwerk verwenden, aber wenn Sie Big Ending-Codierung verwenden, wird dies die Byte-Reihenfolge unnötig umkehren, so dass "if __BYTE_ORDER == __LITTLE_ENDIAN "kann es erforderlich sein, Ihren Code portabler zu machen, abhängig von Ihren Anforderungen.

Update: Bearbeitet, um ein Beispiel für die Endian-Prüfung anzuzeigen

0
jwbensley