68 votes

64 bits ntohl () en C ++?

Les pages de manuel pour htonl() semblent suggérer que vous ne pouvez l'utiliser jusqu'à 32 bits. (En réalité, ntohl() est défini unsigned long, qui, sur ma plate-forme est de 32 bits. Je suppose que si le type unsigned long de 8 octets, il travail pour la version 64 bits ints).

Mon problème est que j'ai besoin de convertir les entiers 64 bits (dans mon cas, c'est un unsigned long long) à partir de gros-boutiste de little-endian. Maintenant, j'ai besoin de faire de conversion spécifique. Mais il serait encore mieux si la fonction (comme ntohl()) ne serait PAS convertir mes 64 bits de la valeur si la plate-forme cible ÉTAIT en big endian. (Je préfère éviter d'ajouter mon propre préprocesseur de la magie pour le faire).

Que puis-je utiliser? Je voudrais quelque chose qui est la norme, si elle existe, mais je suis ouvert à la mise en œuvre des suggestions. J'ai vu ce type de conversion fait dans le passé à l'aide des syndicats. Je suppose que je pourrais avoir une union avec un unsigned long long et un char[8]. Puis le swap d'octets en conséquence. (Bien sûr se briser sur les plates-formes qui ont été en big endian).

61voto

Nanno Langstraat Points 390

Documentation: man htobe64 sur Linux (glibc >= 2.9) ou FreeBSD.

Malheureusement, OpenBSD, FreeBSD et glibc (Linux) n'est pas assez travailler ensemble harmonieusement pour créer une (non-kernel-API) de la libc standard pour cela, au cours d'une tentative en 2009.

Actuellement, ce court peu de préprocesseur 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

(testé sur Linux et OpenBSD) doit masquer les différences. Il vous donne la Linux/FreeBSD-style macros sur ces 4 plates-formes.

Exemple d'utilisation:

  #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 );

C'est le plus "bibliothèque standard C"-ish approche disponible pour le moment.

20voto

user442585 Points 196

Je vous recommande de lire ceci: 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;
}

Va montrer le résultat suivant:

1
72057594037927936
1

Vous pouvez le tester avec ntohl() si vous déposez la partie supérieure de 4 octets.

Aussi, Vous pouvez la transformer en une belle basé sur un modèle de fonction en C++ qui fonctionne sur n'importe quelle taille de l'entier:

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

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

    return output;
}

Maintenant, votre 128 bits aussi la sécurité!

14voto

paxdiablo Points 341644

Pour détecter votre endian-ness, utilisez l'union suivante:

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

Ensuite, vous pouvez vérifier le contenu de x.c[] pour détecter où chaque octet est allé.

Pour faire la conversion, je voudrais utiliser ce code de détection d'une fois pour voir ce que endian-ness la plate-forme est à l'aide de, puis d'écrire mon propre fonction pour faire des échanges.

On pourrait le rendre dynamique, de sorte que le code va s'exécuter sur n'importe quelle plateforme (détecter une seule fois, puis d'utiliser un commutateur à l'intérieur de votre code de conversion de choisir le droit de conversion), mais, si vous allez seulement d'être en utilisant une plate-forme, je venais de faire la détection d'une fois dans un programme distinct, puis le code d'une simple routine de conversion, assurez-vous d'document qui ne fonctionne (ou a été testé) sur cette plate-forme.

Voici un exemple de code que j'ai fouetté jusqu'à l'illustrer. Il a été testé, mais pas d'une manière exhaustive, mais elle devrait être assez pour vous obtenir a commencé.

#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;
}

Gardez à l'esprit qu'il vérifie juste de la pure big/little endian. Si vous avez un peu bizarre variante où les octets sont stockés dans, par exemple, {5,2,3,1,0,7,6,4} ordonnance, cvt() sera un peu plus complexe. Une telle architecture ne mérite pas d'exister, mais je ne suis pas l'actualisation de la folie de nos amis dans l'industrie des microprocesseurs :-)

12voto

Francis Points 4305

Certains systèmes BSD ont betoh64 qui fait ce dont vous avez besoin.

6voto

Sandeep Points 5289

Macro à une ligne pour un échange 64 bits sur de petites machines Endian.

 #define bswap64(y) (((uint64_t)ntohl(y)) << 32 | ntohl(y>>32))
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X