Есть ли "стандартная" htonl-подобная функция для 64-битных целых чисел в C++?

Я работаю над реализацией протокола memcache, который в некоторые моменты использует 64-битные целочисленные значения. Эти значения должны храниться в"сетевом порядке байтов".

жаль, что не было некоторых uint64_t htonll(uint64_t value) функция для изменения, но, к сожалению, если она существует, я не смог ее найти.

Итак, у меня есть 1 или 2 вопроса:

  • есть портативный (Windows, Linux, AIX) стандартная функция для этого ?
  • если нет такая функция, как бы Вы ее реализовали ?

Я имею в виду базовую реализацию, но я не знаю как проверить байтов во время компиляции, чтобы сделать переносимый код. Так что ваша помощь более чем приветствуется здесь ;)

спасибо.


вот окончательное решение, которое я написал, благодаря решению Брайана.

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

6 ответов


вы, вероятно, ищете bswap_64 Я думаю, что он поддерживается практически везде, но я бы не назвал это стандарт.

вы можете легко проверить endianness, создав int со значением 1, приведя адрес вашего int как char* и проверка значения первого байта.

например:

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

зная это, вы также можете сделать простую функцию, которая выполняет замену.


вы также можете всегда использовать boost который содержит макросы endian, которые являются переносной кросс-платформой.


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

тест (1= = htonl (1)) просто определяет (во время выполнения, к сожалению), требует ли аппаратная архитектура замены байтов. Нет никаких портативных способов определить во время компиляции, что такое архитектура, поэтому мы прибегаем к использованию "htonl", который так же портативен, как и в этой ситуации. Если требуется замена байтов, то мы меняем 32 бита за раз, используя htonl (не забывая также менять местами два 32-битных слова).


это, кажется, работает в C; я сделал что-то неправильно?

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

С uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) для наоборот.


чтобы уменьшить накладные расходы "if num == ..." Использование предварительного процессора определяет:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

EDIT: объединение двух (используется код Брайана):

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

предупреждение: непроверенный код! Пожалуйста, проверьте перед использованием.