webentwicklung-frage-antwort-db.com.de

Gibt es eine "Standard" -Htonl-ähnliche Funktion für 64-Bit-Ganzzahlen in C ++?

Ich arbeite an einer Implementierung des Memcache-Protokolls, das an einigen Stellen 64-Bit-Integer-Werte verwendet. Diese Werte müssen in "Netzwerkbyte-Reihenfolge" gespeichert werden.

Ich wünschte, es gäbe eine uint64_t htonll(uint64_t value) - Funktion, um die Änderung durchzuführen, aber leider konnte ich sie nicht finden, wenn sie existiert.

Ich habe also 1 oder 2 Fragen:

  • Gibt es eine portable (Windows, Linux, AIX) Standardfunktion, um dies zu tun?
  • Wenn es keine solche Funktion gibt, wie würden Sie sie implementieren?

Ich habe eine grundlegende Implementierung im Sinn, aber ich weiß nicht, wie ich die Endianness beim Kompilieren überprüfen soll, um den Code portabel zu machen. Eure Hilfe ist hier also mehr als willkommen;)

Vielen Dank.


Hier ist die endgültige Lösung, die ich dank Brians Lösung geschrieben habe.

uint64_t htonll(uint64_t value)
{
    // The answer is 42
    static const int num = 42;

    // Check the endianness
    if (*reinterpret_cast<const char*>(&num) == num)
    {
        const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
        const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

        return (static_cast<uint64_t>(low_part) << 32) | high_part;
    } else
    {
        return value;
    }
}
60
ereOn

Sie suchen wahrscheinlich nach bswap_64 Ich denke, es wird so ziemlich überall unterstützt, aber ich würde es nicht als Standard bezeichnen.

Sie können die Endianness leicht überprüfen, indem Sie ein int mit dem Wert 1 erstellen und die Adresse Ihres int als char* und überprüfe den Wert des ersten Bytes.

Beispielsweise:

int num = 42;
if(*(char *)&num == 42)
{
   //Little Endian
}
else
{
   //Big Endian
} 

Wenn Sie das wissen, können Sie auch eine einfache Funktion erstellen, die das Tauschen übernimmt.


Sie könnten auch immer boost verwenden, das Endian-Makros enthält, die portabel und plattformübergreifend sind.

16
Brian R. Bondy
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

Der Test (1 == htonl (1)) bestimmt einfach (leider zur Laufzeit), ob die Hardwarearchitektur das Austauschen von Bytes erfordert. Es gibt keine portablen Methoden, um beim Kompilieren festzustellen, wie die Architektur aussieht. Daher greifen wir auf "htonl" zurück, das in dieser Situation so portabel wie möglich ist. Wenn das Austauschen von Bytes erforderlich ist, tauschen wir jeweils 32 Bits mit htonl aus (denken Sie daran, auch die beiden 32-Bit-Wörter auszutauschen).


Hier ist eine weitere Möglichkeit, den Swap durchzuführen, der auf den meisten Compilern und Betriebssystemen, einschließlich AIX, BSDs, Linux und Solaris, portierbar ist.

#if __BIG_ENDIAN__
# define htonll(x) (x)
# define ntohll(x) (x)
#else
# define htonll(x) ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# define ntohll(x) ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif

Der wichtige Teil ist die Verwendung von __BIG_ENDIAN__ oder __LITTLE_ENDIAN__; und nicht __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ oder __ORDER_LITTLE_ENDIAN__. Bei einigen Compilern und Betriebssystemen fehlt __BYTE_ORDER__ und Freunde.

15
deltamind106

Sie können es mit uint64_t htobe64(uint64_t Host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) versuchen, und umgekehrt.

5
suresh m

Dies scheint in C zu funktionieren; Habe ich etwas falsch gemacht?

uint64_t htonll(uint64_t value) {
    int num = 42;
    if (*(char *)&num == 42) {
        uint32_t high_part = htonl((uint32_t)(value >> 32));
        uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL));
        return (((uint64_t)low_part) << 32) | high_part;
    } else {
        return value;
    }
}
4
pix0r

Um den Overhead von "if num == ..." zu reduzieren, verwenden Sie den Preprozessor definiert:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif
1
user3734255