Question

Je travaille sur une mise en œuvre du protocole de cache mémoire qui, en certains points, utilise des valeurs entier 64 bits. Ces valeurs doivent être stockées dans « l'ordre des octets du réseau ».

Je souhaite qu'il y ait une fonction de uint64_t htonll(uint64_t value) pour faire le changement, mais malheureusement, si elle existe, je ne pouvais pas le trouver.

J'ai donc 1 ou 2 questions:

  • Y at-il portable (Windows, Linux, AIX) fonction standard pour le faire?
  • S'il n'y a pas une telle fonction, comment voulez-vous le mettre en œuvre?

Je pense une implémentation de base mais je ne sais pas comment vérifier le boutisme à la compilation pour rendre le code portable. Donc, votre aide est ici plus que bienvenus;)

Merci.


Voici la solution finale je l'ai écrit, grâce à la solution de Brian.

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;
    }
}
Était-ce utile?

La solution

Vous cherchez probablement bswap_64 Je pense qu'il est pris en charge à peu près partout, mais je ne l'appellerais pas standard.

Vous pouvez facilement vérifier le boutisme en créant un int avec une valeur de 1, jetant l'adresse de votre int comme char* et vérifier la valeur du premier octet.

Par exemple:

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

Sachant cela, vous pouvez aussi faire une fonction simple qui fait l'échangisme.


Vous pouvez également utiliser toujours coup de pouce qui contient des macros endian qui sont multi-plateforme portable.

Autres conseils

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

Le test (1 == htonl (1)) détermine simplement (à l'exécution malheureusement) si les requres d'architecture matérielle octet de permutation. Il n'y a pas de moyens portables pour déterminer à la compilation ce que l'architecture est, donc nous avons recours à l'utilisation de « htonl », qui est aussi portable qu'il obtient dans cette situation. Si vous avez besoin byte-swapping, nous échangeons des 32 bits à la fois en utilisant htonl (en se souvenant d'échanger les deux mots de 32 bits aussi bien).


Voici une autre façon d'effectuer l'échange qui est portable dans la plupart des compilateurs et systèmes d'exploitation, y compris AIX, BSD, Linux et Solaris.

#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

La partie importante est d'utiliser __BIG_ENDIAN__ ou __LITTLE_ENDIAN__; et non __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ ou __ORDER_LITTLE_ENDIAN__. Certains compilateurs et systèmes d'exploitation manquent __BYTE_ORDER__ et les amis.

Vous pouvez essayer avec uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) pour vice-versa.

Cela semble fonctionner en C; ai-je fait quelque chose de mal?

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

Pour réduire les frais généraux du « si num == ... » Utilisez les définit pré-processeur:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

EDIT: combiner les deux (utilisé le code de Brian):

uint64_t htonll(uint64_t value)
{
     int num = 42;
     if(*(char *)&num == 42)
          return (htonl(value & 0xFFFFFFFF) << 32LL) | htonl(value >> 32);
     else 
          return value;
}

Avertissement: code non testé! S'il vous plaît essai avant d'utiliser.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top