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

StackOverflow https://stackoverflow.com/questions/3022552

Вопрос

Я работаю над реализацией протокола MEMCACHA, который в некоторых моментах использует 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;
    }
}
Это было полезно?

Решение

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

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

Например:

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

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


Вы также можете всегда использовать Boost, который содержит Endian Macros, которые являются портативной поперечной платформой.

Другие советы

#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-битных слова).


Вот еще один способ выполнить своп, который портативный по всему большинству компиляторов и операционных систем, включая AIX, BSDS, Linux и 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

Важная часть - использовать __BIG_ENDIAN__ или __LITTLE_ENDIAN__; и нет __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ или __ORDER_LITTLE_ENDIAN__. Отказ Не хватает некоторых компиляторов и операционных систем __BYTE_ORDER__ и друзья.

Вы можете попробовать с uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) Для вице-версий.

Это кажется, работает в 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;
    }
}

Чтобы уменьшить накладные расходы «Если num == ...», используйте предварительный процессор определяет:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

Редактировать: объединение двух (код брайана):

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top