Выровненные и упакованные атрибуты

Я работаю над прошивкой для 16-битного PIC и пишу на C (компилятор Microchip C30). Мое устройство получает длинный список байтов от внешнего устройства, а затем я пытаюсь скопировать эти байты в структуру. Структура определяется следующим образом:

typedef struct __attribute__((__packed__)) {
    char    F1Nickname[17];
    char    F2Nickname[17];
    DWORD   F1CurrentPos;
    DWORD   F2CurrentPos;
    WORD    F1CurrentTemp;
    WORD    F2CurrentTemp;
    DWORD   F1MaxPos;
    DWORD   F2MaxPos;
    BYTE    F1TempCompOn;
    BYTE    F2TempCompOn;
    BYTE    CheckSum;
} deviceStatus;

У меня была странная проблема: всякий раз, когда общее количество байтов в структуре было нечетным числом, моя программа зависала и попадала в подпрограмму обслуживания AddressError. Я могу исправить проблему, просто добавив дополнительный байт в структуру, но это похоже на временное решение.

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

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

Если я добавлю выровненный атрибут, должен ли я удалить упакованный атрибут? Разве они в основном не делают обратное?


person PICyourBrain    schedule 11.08.2011    source источник
comment
О каком микроконтроллере идет речь? дсПИК?   -  person Vinicius Kamakura    schedule 11.08.2011
comment
Align выровняет его по границе 16-битного адреса.   -  person Tony The Lion    schedule 11.08.2011
comment
Я думаю, ваша проблема в том, что слова и двойные слова должны быть правильно выровнены (что не обязательно будет, если у вас есть упакованная структура). Архитектура устройства требует, чтобы слова были выровнены по четным границам байтов, поэтому необходимо соблюдать осторожность при использовании упакованного атрибута, чтобы избежать ошибок адресации во время выполнения. Из РУКОВОДСТВА ПОЛЬЗОВАТЕЛЯ КОМПИЛЯТОРА C30 C   -  person user786653    schedule 11.08.2011
comment
Если у вас есть контроль как над отправителем, так и над получателем, не можете ли вы добавить отступы, чтобы правильно выровнять все поля? Если у них одинаковая архитектура, вы можете даже удалить атрибут packed и позволить компилятору сделать всю работу.   -  person nmichaels    schedule 11.08.2011
comment
Выровненный — это противоположность упакованному. Выравнивание - это то, что вызывает вставку байтов заполнения.   -  person Hans Passant    schedule 11.08.2011


Ответы (2)


__attribute__ и __packed__ не являются частью стандарта C и являются расширениями, предоставляемыми вашим компилятором. Единственный способ узнать наверняка, что они означают, — это посмотреть в документации компилятора.

person Skizz    schedule 11.08.2011
comment
Идиома __attribute__((__packed__)) кажется идиомой GCC. Один из самых распространенных компиляторов, ISTM. Не стандарт, но и не редкость. - person Rudy Velthuis; 12.08.2011
comment
@Rudy: Правда, многие производители PIC и микроконтроллеров используют интерфейс GCC для своих компиляторов. - person Skizz; 12.08.2011

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

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

person doron    schedule 11.08.2011
comment
на самом деле, многие архитектуры вообще не вызывают исключения, они просто делают не то, что нужно, что может привести к игнорированию младшего значащего бита, преобразованию выборки в микрокоде в многобайтовые инструкции выборки ( при значительном снижении производительности), выборке только части слова или просто входе в неизвестное состояние. - person SingleNegationElimination; 11.08.2011
comment
ISTM, что если платформе требуется выравнивание, ручная сериализация действительно его единственный выход. - person Rudy Velthuis; 12.08.2011