Как я преобразовываю значение от порядка байтов хоста до прямого порядка байтов?

Середина или возможно пользовательские элементы управления Senior

  • Skinning/Themeing
9
задан anorm 9 December 2009 в 11:40
поделиться

6 ответов

Что-то вроде следующего:

unsigned short swaps( unsigned short val)
{
    return ((val & 0xff) << 8) | ((val & 0xff00) >> 8);
}

/* host to little endian */

#define PLATFORM_IS_BIG_ENDIAN 1
#if PLATFORM_IS_LITTLE_ENDIAN
unsigned short htoles( unsigned short val)
{
    /* no-op on a little endian platform */
    return val;
}
#elif PLATFORM_IS_BIG_ENDIAN
unsigned short htoles( unsigned short val)
{
    /* need to swap bytes on a big endian platform */
    return swaps( val);
}
#else
unsigned short htoles( unsigned short val)
{
    /* the platform hasn't been properly configured for the */
    /* preprocessor to know if it's little or big endian    */

    /* use potentially less-performant, but always works option */

    return swaps( htons(val));
}
#endif

Если у вас есть система, которая правильно настроена (так, что препроцессор знает, какой у целевой идентификатор прямой или большой порядок байтов), вы получите «оптимизированную» версию htoles () . В противном случае вы получите потенциально неоптимизированную версию, которая зависит от htons () . В любом случае вы получите что-то, что работает.

Ничего слишком сложного и более или менее переносимого.

Конечно, вы можете еще больше улучшить возможности оптимизации, реализовав это с помощью встроенного или макроса как вы сочтете нужным.

Возможно, вы захотите взглянуть на что-то вроде «Portable Open Source Harness (POSH)» для реальной реализации, которая определяет порядок байтов для различных компиляторов. Запись, чтобы попасть в библиотеку, необходимо пройти через страницу псевдо-аутентификации (хотя вам не нужно регистрироваться, чтобы указать какие-либо личные данные): http://hookatooka.com/poshlib/

4
ответ дан 4 December 2019 в 11:42
поделиться

Вот статья о порядке байтов и о том, как определить их от IBM:

Написание кода, независимого от порядка байтов, на C: не позволяйте порядку байтов «байтовать» вас

Он включает пример того, как определить порядок байтов во время выполнения (что вам нужно будет сделать только один раз)

const int i = 1;
#define is_bigendian() ( (*(char*)&i) == 0 )

int main(void) {
    int val;
    char *ptr;
    ptr = (char*) &val;
    val = 0x12345678;
    if (is_bigendian()) {
        printf(“%X.%X.%X.%X\n", u.c[0], u.c[1], u.c[2], u.c[3]);
    } else {
        printf(“%X.%X.%X.%X\n", u.c[3], u.c[2], u.c[1], u.c[0]);
    }
    exit(0);
}

На странице также есть раздел о методах изменения порядка байтов:

short reverseShort (short s) {
    unsigned char c1, c2;

    if (is_bigendian()) {
        return s;
    } else {
        c1 = s & 255;
        c2 = (s >> 8) & 255;

        return (c1 << 8) + c2;
    }
}

;

short reverseShort (char *c) {
    short s;
    char *p = (char *)&s;

    if (is_bigendian()) {
        p[0] = c[0];
        p[1] = c[1];
    } else {
        p[0] = c[1];
        p[1] = c[0];
    }

    return s;
}
8
ответ дан 4 December 2019 в 11:42
поделиться

Затем вы должны знать порядок байтов и условно вызвать htons (). Собственно даже не htons, а просто условно поменять байты местами. Конечно, во время компиляции.

6
ответ дан 4 December 2019 в 11:42
поделиться

Этот трюк должен: при запуске использовать ntohs с фиктивным значением, а затем сравнивать полученное значение с исходным значением. Если оба значения одинаковы, то машина использует обратный порядок байтов, в противном случае - обратный порядок байтов.

Затем используйте метод ToLittleEndian , который либо ничего не делает, либо вызывает ntohs , в зависимости от по результатам первоначального теста.

(Отредактировано с учетом информации, предоставленной в комментариях)

0
ответ дан 4 December 2019 в 11:42
поделиться

Я предполагаю, что производительность зависит от того, выполняете ли вы с прямым порядком байтов большой блок данных за один раз или только одно значение:

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

Если блок большой, вы можете беспокоиться, что компилятор его не обработает. Так что сделайте что-нибудь вроде этого:

if (!is_little_endian()) {
    for (int i = 0; i < size; ++i) {
        vals[i] = swap_short(vals[i]);
    }
}

Или посмотрите инструкции SIMD для своей архитектуры, которые могут сделать это значительно быстрее.

Напишите is_little_endian () , используя любой трюк, который вам нравится.

0
ответ дан 4 December 2019 в 11:42
поделиться

К сожалению, на самом деле не существует кроссплатформенного способа определения порядка байтов в системе во время компиляции со стандартным C. Я предлагаю добавить #define в ваш config.h (или что-то еще, что вы или ваша система сборки используете для конфигурации сборки).

Модульный тест для проверки правильности определения из LITTLE_ENDIAN или BIG_ENDIAN могут выглядеть следующим образом:

#include <assert.h>
#include <limits.h>
#include <stdint.h>

void check_bits_per_byte(void)
{ assert(CHAR_BIT == 8); }

void check_sizeof_uint32(void)
{ assert(sizeof (uint32_t) == 4); }

void check_byte_order(void)
{
    static const union { unsigned char bytes[4]; uint32_t value; } byte_order =
        { { 1, 2, 3, 4 } };

    static const uint32_t little_endian = 0x04030201ul;
    static const uint32_t big_endian = 0x01020304ul;

    #ifdef LITTLE_ENDIAN
    assert(byte_order.value == little_endian);
    #endif

    #ifdef BIG_ENDIAN
    assert(byte_order.value == big_endian);
    #endif

    #if !defined LITTLE_ENDIAN && !defined BIG_ENDIAN
    assert(!"byte order unknown or unsupported");
    #endif
}

int main(void)
{
    check_bits_per_byte();
    check_sizeof_uint32();
    check_byte_order();
}
0
ответ дан 4 December 2019 в 11:42
поделиться