Yaumen 0 9 ноября, 2009 Опубликовано 9 ноября, 2009 (изменено) · Жалоба В программе, написанной на C++ (Keil) для LPC2366 обнаружилась следующая проблема при работе с массивом: Вот оптимизированный для просмотра отрывок из программы: BYTE byData[8] = {0x12, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x02, 0x00}; BYTE* prtBuf = (BYTE*)byData; DWORD dwVal1 = *((DWORD*)(prtBuf)); DWORD dwVal2 = *((DWORD*)(prtBuf + 1)); DWORD dwVal3 = *((DWORD*)(prtBuf + 2)); DWORD dwVal4 = *((DWORD*)(prtBuf + 4)); На выходе получаю следующие значения: dwVal1 = 0x000A0012; dwVal2 = 0x12000A00; dwVal3 = 0x0012000A; dwVal4 = 0x00020001; Ошибка возникает в значении dwVal2 и dwVal3, т.е. при смещении относительно начала массива, не кратно DWORD. Из-за чего это происходит и можно ли с этим бороться!? Изменено 9 ноября, 2009 пользователем Yaumen Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Из-за чего это происходит и можно ли с этим бороться!? Из-за того, что ARM7 сам по себе не умеет читать слова по невыровненным адресам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Yaumen 0 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Из-за того, что ARM7 сам по себе не умеет читать слова по невыровненным адресам. Т.е. или все выравнивать или формировать DWORD самому, считывая побайтно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Ну, не обязательно самому, можно написать: DWORD dwVal2 = *((__packed DWORD*)(prtBuf + 1)); Но лучше, естественно, выравнивать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Т.е. или все выравнивать или формировать DWORD самому, считывая побайтно? Вообще-то крайне желательно с форумом ознакомится - вопрос обыденный. Только с неделю назад очередное обострение было. Руками незачем. Лучше поставить правильно задачу компилятору правильно описав данные. На худой конец memcpy(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
koyodza 0 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Вообще-то крайне желательно с форумом ознакомится - вопрос обыденный. Только с неделю назад очередное обострение было. Руками незачем. Лучше поставить правильно задачу компилятору правильно описав данные. На худой конец memcpy(). memcpy тоже лажался на невыровненных 32-битных переменных (float в т.ч.) Подробностей уже не помню, разбирался с проблемой недолго. Решение было принято радикальное - "ручная сборка" длинных данных из невыровненных. Сейчас на Cortex такой проблемы нет Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Подробностей уже не помню... Не надо рассказывать байки, тем более, которые не помните. memcpy(), как минимум, не знает ведать не ведает ни о каких типах данных, поскольку работает исключительно с void *. По этой банальной причине он просто не способен различить float и не способен с ним работать иначе и неправильнее чем с любым другим типом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Yaumen 0 10 ноября, 2009 Опубликовано 10 ноября, 2009 · Жалоба А будет ли та же проблема со структурой, объявленной как: #pragma pack(1) struct MSGHEADER { BYTE ... BYTE ... BYTE ... WORD wParameter }; #pragma pack() т.е. смогу ли нормально вычитать WORD переменную: WORD wVal = pMsg->wParameter или тоже будут проблемы с выравниванием? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 10 ноября, 2009 Опубликовано 10 ноября, 2009 · Жалоба Проблем быть не должно - будет медленное обращение по байтам с последующим "склеиванием". Соответственно, если хочется скорости работы, лучше так не делать. Да, если сделать, например, так: int fnc (WORD *ptr); ... fnc (&pMsg->wParameter); проблема будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
koyodza 0 10 ноября, 2009 Опубликовано 10 ноября, 2009 · Жалоба Не надо рассказывать байки, тем более, которые не помните. memcpy(), как минимум, не знает ведать не ведает ни о каких типах данных, поскольку работает исключительно с void *. По этой банальной причине он просто не способен различить float и не способен с ним работать иначе и неправильнее чем с любым другим типом. Посмотрите там: http://www.alylab.eu/Subjects/STR91x/STR91x.htm "Команда memcpy((void*)dst_buf,(void*)src_buf2,4) даже при 0-ом уровне оптимизации может быть превращена в простую пересылку 32-х разрядных регистров..." Я столкнулся с этим на LPC (кажется, это был 2138), но я уже знал тогда о потенциальной проблеме (из указанного источника) и обошел её именно "ручным" копированием. Перед этим коллеги столкнулись с "необъяснимыми глюками" (как они говорили) на ADUC7024, и сами обошли тем же способом. Я не разбирался, чей это глюк - ядра или кейла, ни желания, ни времени на это не было. Последнее время работаю с STM32 (именно в кейле) - этой проблемы не возникало. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 10 ноября, 2009 Опубликовано 10 ноября, 2009 · Жалоба кейла, ни желания, ни времени на это не было. Явный чистейшей воды баг Кейла. Подлежит исправлению, что и сделали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
koyodza 0 9 февраля, 2010 Опубликовано 9 февраля, 2010 · Жалоба Явный чистейшей воды баг Кейла. Подлежит исправлению, что и сделали. А как Вы прокомментируете это? By default, ARM7 and ARM9 based microcontrollers do not allow un-aligned accesses to 16-bit and 32-bit data types. http://www.keil.com/support/docs/3194.htm Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 9 февраля, 2010 Опубликовано 9 февраля, 2010 · Жалоба Хм. А какой комментарий вы рассчитываете получить к изложению общеизвестной архитектурной особенности? "Баг Кейла", как я понимаю, заключался в замене вызова memcpy на LDR/STR при высоком уровне оптимизации без контроля выравнивания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться