Domanda

sto lavorando un'implementazione del protocollo memcache che, in alcuni punti, utilizza 64 bit integer valori. Questi valori devono essere conservati in "ordine di byte di rete".

Vorrei che ci fosse qualche funzione uint64_t htonll(uint64_t value) per fare il cambiamento, ma purtroppo, se esiste, non ho potuto trovarlo.

Così ho 1 o 2 domande:

  • C'è un portatile (Windows, Linux, AIX) funzione standard per fare questo?
  • Se non c'è tale funzione, come è possibile implementarlo?

Ho in mente un'implementazione di base, ma non so come controllare l'endianness a tempo di compilazione per rendere il codice portabile. Quindi, il vostro aiuto è più che benvenuto qui;)

Grazie.


Ecco la soluzione definitiva che ho scritto, grazie alla soluzione di 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;
    }
}
È stato utile?

Soluzione

Probabilmente si sta cercando bswap_64 penso che è supportato un po 'ovunque, ma io non la chiamerei standard.

È possibile controllare facilmente l'endianness con la creazione di un int con un valore di 1, gettando l'indirizzo del tuo int come char* e controllare il valore del primo byte.

Ad esempio:

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

Sapendo questo si potrebbe anche fare una semplice funzione che fa lo scambio.


Si potrebbe anche utilizzare sempre spinta che contiene le macro endian che sono cross-platform portatili.

Altri suggerimenti

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

Il test (1 == htonl (1)) determina semplicemente (a runtime purtroppo) se i Requres architettura hardware byte scambio. Non ci sono modi portatili per determinare al momento della compilazione ciò che l'architettura è, quindi si ricorre all'utilizzo di "htonl", che è il più portabile come si arriva in questa situazione. Se è richiesta byte-swap, allora scambiamo 32 bit alla volta utilizzando htonl (ricordando di scambiare le due parole a 32 bit così).


Ecco un altro modo per eseguire lo swap che è portabile sulla maggior parte dei compilatori e sistemi operativi, tra cui AIX, BSD, Linux e 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 è quello di utilizzare __BIG_ENDIAN__ o __LITTLE_ENDIAN__; e non __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ o __ORDER_LITTLE_ENDIAN__. Alcuni compilatori e sistemi operativi mancano __BYTE_ORDER__ e gli amici.

Si può provare con uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) per viceversa.

Questo sembra funzionare in C; ho fatto qualcosa di sbagliato?

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

Per ridurre l'overhead del "se num == ..." Utilizzare le definisce pre-processore:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

EDIT: combinando la (codice utilizzato di Brian) due:

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

Attenzione: codice non testato! Si prega di prova prima di utilizzare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top