Перейти к содержанию
    

Что-то я совсем потерялся....

 

Что в процах с 32 битным выравниванием данных прямые бездумные обращения к памяти чреваты - это точно. В таких процах создание массивов элементов размера не кратного 32 битам и бездумное обращение с ними как с памятью - тоже чревато.

 

А вот объяснения и примера я чет хорошего придумать не могу%(.... вы все врем меня стандартами языка придавливаете:(....

Вы почему-то путаете невыровненный доступ CPU и работу си-компиляторов со структурами.

Это две не относящиеся друг к другу вещи.

Во всех примерах, что я привел нигде нет невыровненного доступа. Даже в случаях с пакованными структурами. :)

В случае с пакованной структурой, вы указываете (величиной паковки в pack()) инструкциями какой максимальной длины

следует обращаться к элементам структуры.

Таким образом, чтение элемента T::a

#pragma pack(push, 1)

struct T { u32 a; };

#pragma pack(pop)

на ARM7/9 будет осуществляться 4-мя байтовыми LDRB с последующей склейкой байт в u32.

Для:

#pragma pack(push, 2)

struct T { u32 a; };

#pragma pack(pop)

на ARM7/9 сгенерит две LDRH с последующей склейкой в u32.

 

Для Cortex-M3 компилятор имеет право сгенерить в обоих случаях одну невыровненную LDR (если, как указал уважаемый Сергей Борщ,

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

А может он просто - поступает так же, как для ARM7/9. Не помню.

 

Так что в обоих случаях - с пакованными и непакованными структурами никаких проблем нет.

Проблема возникает только когда вы обманываете компилятор - подсовываете адрес в указатель на структуру и выравнивание этого адреса не соответствует

выравниванию структуры. Выравнивание непакованной структуры всегда равно выравниванию максимального её члена, выравнивание пакованной - не превышает

величины паковки.

 

PS: Я кстати стараюсь не пользоваться пакованными структурами. А там, где это нужно (например - для описания форматов кадров протоколов обмена),

предпочитаю в качестве членов структур, размер которых превышает выравнивание структуры, использовать свои типы данных, реализованные классами с

соответствующими методами доступа к ним.

В таком случае не возникает проблем с указателями на пакованные структуры в компиляторе.

И что ещё более важно - такие описания структур легко переносятся между разными компиляторами, так как не привязаны к прагмам, которые в разных компиляторах = разные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы почему-то путаете не выровненный доступ CPU и работу си-компиляторов со структурами

Очевидно вы правы, я смешал 2 независимые вещи...

 

Что-то мне казалось что в зависимости от типа проца (от величины его выравнивания), среда задает такой же параметр паковки структур по умолчанию. Вероятно это скорее исключение чем правило, но мне сейчас кажется что я пару раз на такое нарывался...

 

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

 

Вот и теперь я понял откуда растут проблемы которые я пытался описать:

Когда с обоих концов стоит проц и язык С, проблемы реально мной надуманы. А вот когда у вас посылки делает проц с языком С, а приемник у вас ПЛИС с автоматом разбора входящего сообщения, вот тут проблемы не пакованных структур и вопросы понимания что как лежит в памяти встают в полный рост!

 

 

 

 

Также вот такой пример мне вспомнился

 

struct __packed str
{
   char A;
   char B;
}

если есть функция передачи 1 поля структуры, по UART, например, то попытки разбора аля

memcpy((void *)&my_str.B, data, 1);

также будут проблеммными, для процов с не байтным выравниванием

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то мне казалось что в зависимости от типа проца (от величины его выравнивания), среда задает такой же параметр паковки структур по умолчанию. Вероятно это скорее исключение чем правило, но мне сейчас кажется что я пару раз на такое нарывался...

От CPU зависит только максимальное выравнивание. Т.е. - struct T { u32 a; }; для 32-битных CPU будет выровнена на 32, а для 16-битных CPU - на 16.

В соответствии с основной разрядностью CPU.

 

struct __packed str
{
   char A;
   char B;
}

если есть функция передачи 1 поля структуры, по UART, например, то попытки разбора аля

memcpy((void *)&my_str.B, data, 1);

также будут проблеммными, для процов с не байтным выравниванием

А в чём тут проблема? В поле my_str.B будет скопирован 1 char из data. С любым выравниванием.

Ну кроме процов, где char - не байт, а другой размер. Но там тоже всё ок, только будет скопирован не байт, а char ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

struct __packed str
{
   char A;
   char B;
}

 

если экземпляр этой структуры my_str лежит, допустим, по адресу 0, и у нас проц типа кортекса М0, с 32 битным выравниванием памяти.

 

какой адрес будет иметь my_str.B? числовое значение? что передастся в memcpy? чем закончится вызов? и где окажутся в итоге данные?

 

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да какое тут 32-битное выравнивание???

Кроме 32-битных инструкций (LDR/STR), у ARM-ов есть и 8-и (LDRB/STRB) и 16-битные (LDRH/STRH) инструкции доступа к памяти.

И выравнивание зависит от разрядности инструкции.

Для байтовых переменных будет конечно-же использованы LDRB/STRB (или LDRSB/STRSB).

и ваш пример будет выполнен корректно.

 

Иначе - следуя вашей логике, когда вы объявляете переменную размером байт, у вас всегда бы выделялось 32 бита памяти под неё.

Но это-же бред.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

что передастся в memcpy? чем закончится вызов? и где окажутся в итоге данные?
Для ответа на этот вопрос достаточно прочитать (нагуглить) описание memcpy(). Она работает с любыми адресами и любым выравниванием. Снаружи это выглядит, как будто она копирует побайтно (и при таком копировании проблем возникнуть не может). Внутри же она может вызывать различные ветки своего алгоритма в зависимости от фактических аргументов (т.е. может скопировать 3 байта до невыровненного адреса побайтно а потом перейти на копирование 4-байтных выровненных слов, потом аналогично побайтно скопировать оставшиеся 3..1 байт, может делать так независимо для источника и приемника), а может подставить одну-две-три команды в точку вызова, если все параметры известны на момент компиляции - это уже забота компилятора и его оптимизатора. В общем с memcpy работать будет всегда.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...