Pregunta

Estoy trabajando en una implementación del protocolo memcache que, en algunos puntos, utiliza 64 bits de número entero valores. Estos valores deben ser almacenados en "orden de bytes de red".

Me gustaría que hubiera alguna función uint64_t htonll(uint64_t value) para hacer el cambio, pero por desgracia, si existe, no pude encontrarlo.

Así que tengo 1 o 2 preguntas:

  • ¿Hay alguna portátil (Windows, Linux, AIX) función estándar de hacer esto?
  • Si no existe tal función, ¿cómo ponerlo en práctica?

Tengo en mente una implementación básica, pero no sé cómo comprobar el orden de bits en tiempo de compilación para hacer el código portátil. Por lo que su ayuda es más que bienvenido 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;
    }
}
¿Fue útil?

Solución

Usted probablemente está buscando bswap_64 Creo que es compatible prácticamente en todas partes, pero yo no diría que es estándar.

Se puede comprobar fácilmente el orden de bits mediante la creación de un int con un valor de 1, echando la dirección de su int como char* y comprobando el valor del primer byte.

Por ejemplo:

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

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


También podría utilizar siempre impulso que contiene macros endian que son multiplataforma portátil.

Otros consejos

#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 (en tiempo de ejecución por desgracia) si los requres arquitectura de hardware de byte swapping. No hay maneras portátiles para determinar en tiempo de compilación lo que es la arquitectura, por lo que se recurre a la utilización de "htonl", que es tan portátil como se pone en esta situación. Si se requiere byte-swapping, entonces intercambiamos 32 bits a la vez usando htonl (recordando para intercambiar los dos 32 palabras de bits también).


Aquí hay otra manera de realizar el canje que es portable a través de la mayoría de los compiladores y sistemas operativos, incluyendo AIX, BSD, Linux y 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 parte importante es usar __BIG_ENDIAN__ o __LITTLE_ENDIAN__; y no __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ o __ORDER_LITTLE_ENDIAN__. Algunos compiladores y sistemas operativos carecen de amigos y __BYTE_ORDER__.

Puede probar con uint64_t htobe64(uint64_t host_64bits) y uint64_t be64toh(uint64_t big_endian_64bits) para vice-versa.

Esto parece funcionar en C; hice mal algo?

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

Para reducir la sobrecarga de la "si num == ..." Usa los define pre-procesador:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

EDIT: la combinación de la (código de Brian utilizado) dos:

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, antes de usar la prueba.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top