Est-il « standard » htonl-like fonction pour des nombres entiers de 64 bits en C ++?
-
26-09-2019 - |
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;
}
}
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.