jcxz 242 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Что-то я совсем потерялся.... Что в процах с 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: Я кстати стараюсь не пользоваться пакованными структурами. А там, где это нужно (например - для описания форматов кадров протоколов обмена), предпочитаю в качестве членов структур, размер которых превышает выравнивание структуры, использовать свои типы данных, реализованные классами с соответствующими методами доступа к ним. В таком случае не возникает проблем с указателями на пакованные структуры в компиляторе. И что ещё более важно - такие описания структур легко переносятся между разными компиляторами, так как не привязаны к прагмам, которые в разных компиляторах = разные. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Вы почему-то путаете не выровненный доступ CPU и работу си-компиляторов со структурами Очевидно вы правы, я смешал 2 независимые вещи... Что-то мне казалось что в зависимости от типа проца (от величины его выравнивания), среда задает такой же параметр паковки структур по умолчанию. Вероятно это скорее исключение чем правило, но мне сейчас кажется что я пару раз на такое нарывался... Отсюда следуют не плотно лежащие данные структуры, а отсюда следуют проблемы при обращении в поля структуры через указатели памяти при всяких функциях пересылки, где структура представлена как байтовый массив, например. Вот и теперь я понял откуда растут проблемы которые я пытался описать: Когда с обоих концов стоит проц и язык С, проблемы реально мной надуманы. А вот когда у вас посылки делает проц с языком С, а приемник у вас ПЛИС с автоматом разбора входящего сообщения, вот тут проблемы не пакованных структур и вопросы понимания что как лежит в памяти встают в полный рост! Также вот такой пример мне вспомнился struct __packed str { char A; char B; } если есть функция передачи 1 поля структуры, по UART, например, то попытки разбора аля memcpy((void *)&my_str.B, data, 1); также будут проблеммными, для процов с не байтным выравниванием Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Что-то мне казалось что в зависимости от типа проца (от величины его выравнивания), среда задает такой же параметр паковки структур по умолчанию. Вероятно это скорее исключение чем правило, но мне сейчас кажется что я пару раз на такое нарывался... От 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 ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба struct __packed str { char A; char B; } если экземпляр этой структуры my_str лежит, допустим, по адресу 0, и у нас проц типа кортекса М0, с 32 битным выравниванием памяти. какой адрес будет иметь my_str.B? числовое значение? что передастся в memcpy? чем закончится вызов? и где окажутся в итоге данные? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Да какое тут 32-битное выравнивание??? Кроме 32-битных инструкций (LDR/STR), у ARM-ов есть и 8-и (LDRB/STRB) и 16-битные (LDRH/STRH) инструкции доступа к памяти. И выравнивание зависит от разрядности инструкции. Для байтовых переменных будет конечно-же использованы LDRB/STRB (или LDRSB/STRSB). и ваш пример будет выполнен корректно. Иначе - следуя вашей логике, когда вы объявляете переменную размером байт, у вас всегда бы выделялось 32 бита памяти под неё. Но это-же бред. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба что передастся в memcpy? чем закончится вызов? и где окажутся в итоге данные?Для ответа на этот вопрос достаточно прочитать (нагуглить) описание memcpy(). Она работает с любыми адресами и любым выравниванием. Снаружи это выглядит, как будто она копирует побайтно (и при таком копировании проблем возникнуть не может). Внутри же она может вызывать различные ветки своего алгоритма в зависимости от фактических аргументов (т.е. может скопировать 3 байта до невыровненного адреса побайтно а потом перейти на копирование 4-байтных выровненных слов, потом аналогично побайтно скопировать оставшиеся 3..1 байт, может делать так независимо для источника и приемника), а может подставить одну-две-три команды в точку вызова, если все параметры известны на момент компиляции - это уже забота компилятора и его оптимизатора. В общем с memcpy работать будет всегда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 12 мая, 2014 Опубликовано 12 мая, 2014 · Жалоба Ладно, сдаюсь... все всегда будет работать хорошо, уговорили.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Belikov_lp 0 18 мая, 2014 Опубликовано 18 мая, 2014 · Жалоба Алгоритмы не пробовал добавлять? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться