Удобный способ использовать большой и маленький порядок байтов одновременно? - PullRequest
0 голосов
/ 04 мая 2018

Мой компилятор поддерживает так называемые "квалификаторы типов" __bigendian и __littleendian.
Моя переменная Buffer выглядит так:

static union
{
    uint8 as_byte[10];
    __bigendian uint16 as_big_endian[5];
    uint16 as_little_endian[5];
} Buffer;

В моем случае микроконтроллер имеет младший порядок байтов, однако для некоторого интерфейса связи мне нужны 16-битные единицы в формате с прямым порядком байтов.
Микроконтроллер поддерживает инструкцию byte swap, которая компилируется в случае использования этих классификаторов типов, так что на самом деле это, кажется, удобный путь.
В руководстве по компилятору сказано, что я должен избегать использования «определителей типов» из-за проблем с переносимостью - конечно!

Мне просто интересно, есть ли лучший способ, чем использование байтового доступа и выполнение перестановки вручную в зависимости от порядкового номера цели?

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

Буфер протокола решит проблему с порядком байтов, но у него есть накладные расходы на обработку / обработку памяти. Пожалуйста, обратитесь https://developers.google.com/protocol-buffers/

0 голосов
/ 04 мая 2018

Лучшее решение - вообще не использовать объединение, а определить порядок байтов uint8_t byte[10];. Если вы решите сказать, что порядок байтов этого массива, например,

[0]=MSB0 [1]=LSB0 [2]=MSB1 [3]=LSB1... 

и проконтролированы бесконечные циклы процессора, затем вы можете получить к ним доступ:

size_t index = i*2; // assuming i is 0 to 5
uint16_t word = (uint16_t)byte[index] << 8 | 
                (uint16_t)byte[index+1];

word теперь содержит MSB и LSB в правильных местах, независимо от порядка процессора. Код является переносимым. Ключевым моментом здесь является использование битовых сдвигов, они превосходят любой другой метод (объединения, арифметика указателей и т. Д.).

Что касается отправки этого по протоколу с известным большим порядком байтов, просто захватите байты в ожидаемом порядке. В этом случае простой for(size_t i=0; i<10; i++).

0 голосов
/ 04 мая 2018

Существуют более или менее стандартные функции ntohl (32 бита), ntohs (16 бит) и их аналоги htonl и htons.

Эти функции конвертируют из порядкового номера в сети и из порядкового номера в сети соответственно.

Порядковый номер в сети всегда имеет большой порядковый номер.

Порядковый номер узла зависит от вашей цели.

Эти функции обычно реализуются с помощью комментируемых вами инструкций (перестановка байтов и т. П.), И использование директив препроцессора компилятора включает их или является просто noop.

Ваш компилятор может уже поддерживать их.

Но, например, типичная реализация будет выглядеть так:

#if TARGET_IS_LITTLE_ENDIAN
    static inline uint32_t ntohl(uint32_t x) {
        //Do actual 32 bit swap
        return swap32(x);
    }
    static inline uint16_t ntohs(uint16_t x) {
        //Do actual 16 bit swap
        return swap16(x);
    }
#else
    #define ntohl(x) (x)
    #define ntohs(x) (x)
#endif

#define htonl(x) ntohs(x)
#define htons(x) ntohs(x)

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

Наконец, вы вызываете эти функции только в реальных функциях приема / передачи. В любой другой части вашей программы вы будете работать только в host endian.

Кроме того, на основе этих функций вы можете легко реализовать свои пользовательские функции ntoh_structure:

ntoh_struct(my_struct *st) {
    st->fieldA=ntohl(st->fieldA);
    st->fieldB=ntohl(st->fieldB);
}
#define hton_struct(st) ntoh_struct(st)

, который, опять же, будет использоваться только при фактическом приеме / передаче данных.


Обратите внимание, что реализация функций swapXX зависит от цели и компилятора.

Реализация, следующая вашему примеру (которую я на самом деле раньше не видел), для C языка будет выглядеть следующим образом:

typedef union {
    __bigendian uint16_t be;
    uint16_t le;
} Buffer16;
typedef union {
    __bigendian uint32_t be;
    uint32_t le;
} Buffer32;

static inline uint16_t swap16(uint16_t x) {
    Buffer16 aux;
    aux.be=x;
    return aux.le;
}
static inline uint32_t swap32(uint32_t x) {
    Buffer32 aux;
    aux.be=x;
    return aux.le;
}
...