¿Hay alguna función htonl" estándar " para enteros de 64 bits en C++?


Estoy trabajando en una implementación del protocolo memcache que, en algunos puntos, utiliza valores enteros de 64 bits. Estos valores deben almacenarse en "orden de bytes de red".

Desearía que hubiera alguna función uint64_t htonll(uint64_t value) para hacer el cambio, pero desafortunadamente, si existe, no pude encontrarla.

Así que tengo 1 o 2 preguntas:

  • ¿Hay alguna función estándar portable (Windows, Linux, AIX) para hacer esto ?
  • Si no existe tal función, ¿cómo implementaría ¿eso ?

Tengo en mente una implementación básica pero no se como comprobar la endianidad en tiempo de compilación para hacer el código portable. Así que su ayuda es más que bienvenida aquí;)

Gracias.


Aquí está la solución final que escribí, gracias a la solución 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;
    }
}
Author: ereOn, 2010-06-11

6 answers

Probablemente esté buscando bswap_64 Creo que es compatible prácticamente en todas partes, pero no lo llamaría estándar.

Puede comprobar fácilmente la endianidad creando un int con un valor de 1, fundiendo la dirección de su int como un char* y comprobando el valor del primer byte.

Por ejemplo:

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

Sabiendo esto, también podría hacer una función simple que haga el intercambio.


También puede utilizar siempre boost que contiene macros endian que son plataforma cruzada portátil.

 17
Author: Brian R. Bondy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-11 12:23:18
#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))

La prueba (1==htonl(1)) simplemente determina (tristemente en tiempo de ejecución) si la arquitectura de hardware requiere intercambio de bytes. No hay ninguna forma portable de determinar en tiempo de compilación cuál es la arquitectura, por lo que recurrimos al uso de "htonl", que es tan portable como lo es en esta situación. Si se requiere intercambio de bytes, entonces intercambiamos 32 bits a la vez usando htonl (recordando intercambiar las dos palabras de 32 bits también).

 14
Author: deltamind106,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-19 14:55:21

Esto parece funcionar en C; ¿hice algo malo?

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
Author: pix0r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-08 16:47:26

Puedes probar con uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) para viceversa.

 4
Author: suresh m,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-23 04:00:16

Para reducir la sobrecarga del "if num == ..." Use el pre-procesador define:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif
 1
Author: user3734255,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-12 13:27:28

EDITAR: combinando los dos (usado el código 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;
}

Advertencia: ¡código no probado! Por favor, pruebe antes de usar.

 -3
Author: Pavel Radzivilovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-11 12:42:09