C - структура с прямым порядком байтов взаимопревращает с структурой с прямым порядком байтов - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть две структуры, которые имеют одинаковые элементы данных.(одна - это big_endian структура, другая - little_endian ), теперь я должен преобразовать их.Но когда я кодировал, я обнаружил, что есть много повторяющихся кодов с небольшими изменениями.Как я могу изменить эти коды, чтобы они были более элегантными без повторного кода ?(Повторный код означает, что эти коды могут быть похожими, например mode == 1 и mode == 2, которые отличаются только позицией назначения. Это не выглядит элегантно, но работает.)

вот мой код:

#pragma scalar_storage_order big-endian

typedef struct {   
    int a1;    
    short a2;    
    char a3;    
    int a4;    
} test_B;

#pragma scalar_storage_order default

typedef struct {
    int a1;    
    short a2;    
    char a3;    
    int a4;    
} test_L;


void interconvert(test_L *little, test_B *big, int mode) {
    // if mode == 1 , convert little to big    
    // if mode == 2 , convert big to little    
    // it may be difficult and redundant when the struct has lots of data member!    
    if(mode == 1) {
        big->a1 = little->a1;
        big->a2 = little->a2;
        big->a3 = little->a3;
        big->a4 = little->a4;
    }
    else if(mode == 2) {
        little->a1 = big->a1;
        little->a2 = big->a2;
        little->a3 = big->a3;
        little->a4 = big->a4;
    }
    else return;
}

Примечание. Приведенный выше код должен работать на gcc-7 или выше , из-за #pragma scalar_storage_order

1 Ответ

0 голосов
/ 26 декабря 2018

Был опубликован ответ, в котором предлагалось использовать memcpy для этой проблемы, но этот ответ был удален.На самом деле этот ответ был правильным, если его использовать правильно, и я хочу объяснить, почему.

#pragma, заданная OP, является центральной, как он отмечает:

Примечание:приведенный выше код должен выполняться на gcc-7 или выше из-за #pragma scalar_storage_order

Структура из OP:

#pragma scalar_storage_order big-endian
typedef struct {   
    int a1;    
    short a2;    
    char a3;    
    int a4;    
} test_B;

означает, что инструкция "test_B.a2 = 256"записывает в двух последовательных байтах, принадлежащих члену a2, соответственно 1 и 0. Это big-endian.Аналогичная инструкция «test_L.a2 = 256» вместо этого будет обрабатывать байты 0 и 1 (младший порядковый номер).

Следующий memcpy:

memcpy(&test_L, &test_B, sizeof test_L)

сделает байты для test_L.a2равно 1 и 0, потому что это содержимое оперативной памяти test_B.a2.Но теперь, читая test_L.a2 в режиме с прямым порядком байтов, эти два байта означают 1. Мы записали 256 и прочитали обратно 1. Это именно то, что нужно для преобразования.

Чтобы правильно использовать этот механизм, достаточно написатьв одной структуре, memcpy () в другой, и читать другую - член за членом.То, что было big-endian, становится little-endian и наоборот.Конечно, если намерение состоит в том, чтобы разработать данные и применить к ним расчеты, важно знать, какой порядковый номер имеют данные;если он соответствует режиму по умолчанию, преобразование не должно выполняться до вычислений, но преобразование должно быть применено позже.Напротив, если входящие данные не соответствуют «порядку байтов по умолчанию» процессора, они должны быть преобразованы в первую очередь.


РЕДАКТИРОВАТЬ После комментария ОП ниже, я исследовал больше.Я посмотрел на это https://gcc.gnu.org/onlinedocs/gcc/Structure-Layout-Pragmas.html

Ну, есть три #pragma, доступных для выбора структуры байтов: big-endian , little-endian , и по умолчанию .Один из первых двух равен последнему: если целевая машина имеет порядок с прямым порядком байтов, значение по умолчанию означает порядок с прямым порядком байтов;если это big-endian, default означает big-endian.Это более чем логично.

Итак, выполнение memcpy () между big-endian и default ничего не делает на машине с прямым порядком байтов;и это тоже логично.Хорошо, лучше подчеркнуть, что memcpy () сама по себе абсолютно ничего не делает: она только перемещает данные из области памяти, обработанной определенным образом, в другую область, обработанную другим способом.Две разные области обрабатываются по-разному, только когда осуществляется нормальный доступ к члену: здесь можно сыграть # pragma scalar_storage_order .И, как я писал ранее, важно знать, какие данные имеют данные, поступающие в программу.Например, если они приходят из сети TCP, мы знаем, что это big-endian;В общем, если оно взято извне «программы» и соблюдает протокол, мы должны знать, что такое порядок байтов.

Для преобразования из порядкового номера в другой нужно использовать маленький и большой , НЕ по умолчанию, потому что это по умолчанию , безусловно, равно одному из первых двух.


Еще одно редактирование

Стимулировано комментариями, и Джеймслин, который использовал онлайн-компилятор, я тоже пытался это сделать.По этому адресу http://tpcg.io/lLe5EW есть демонстрация того, что при присваивании члену одной структуры, memcpy другому и чтении этого, выполняется преобразование в порядок байтов.Вот и все.

...