реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Ошибка считывание DWORD данных из BYTE массива
Yaumen
сообщение Nov 9 2009, 14:36
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213



В программе, написанной на 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. Из-за чего это происходит и можно ли с этим бороться!?

Сообщение отредактировал Yaumen - Nov 9 2009, 14:43
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Nov 9 2009, 14:50
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Yaumen @ Nov 9 2009, 17:36) *
Из-за чего это происходит и можно ли с этим бороться!?

Из-за того, что ARM7 сам по себе не умеет читать слова по невыровненным адресам.
Go to the top of the page
 
+Quote Post
Yaumen
сообщение Nov 9 2009, 14:59
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213



Цитата(aaarrr @ Nov 9 2009, 16:50) *
Из-за того, что ARM7 сам по себе не умеет читать слова по невыровненным адресам.


Т.е. или все выравнивать или формировать DWORD самому, считывая побайтно?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Nov 9 2009, 15:02
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Ну, не обязательно самому, можно написать:
Код
DWORD dwVal2 = *((__packed DWORD*)(prtBuf + 1));


Но лучше, естественно, выравнивать.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Nov 9 2009, 15:05
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Yaumen @ Nov 9 2009, 17:59) *
Т.е. или все выравнивать или формировать DWORD самому, считывая побайтно?

Вообще-то крайне желательно с форумом ознакомится - вопрос обыденный. Только с неделю назад очередное обострение было.
Руками незачем. Лучше поставить правильно задачу компилятору правильно описав данные. На худой конец memcpy().


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
koyodza
сообщение Nov 9 2009, 17:54
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 213
Регистрация: 28-02-07
Из: Киев
Пользователь №: 25 744



Цитата(zltigo @ Nov 9 2009, 17:05) *
Вообще-то крайне желательно с форумом ознакомится - вопрос обыденный. Только с неделю назад очередное обострение было.
Руками незачем. Лучше поставить правильно задачу компилятору правильно описав данные. На худой конец memcpy().

memcpy тоже лажался на невыровненных 32-битных переменных (float в т.ч.)
Подробностей уже не помню, разбирался с проблемой недолго. Решение было принято радикальное - "ручная сборка" длинных данных из невыровненных.
Сейчас на Cortex такой проблемы нет
Go to the top of the page
 
+Quote Post
zltigo
сообщение Nov 9 2009, 18:09
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(koyodza @ Nov 9 2009, 20:54) *
Подробностей уже не помню...

Не надо рассказывать байки, тем более, которые не помните. memcpy(), как минимум, не знает ведать не ведает ни о каких типах данных, поскольку работает исключительно с void *. По этой банальной причине он просто не способен различить float и не способен с ним работать иначе и неправильнее чем с любым другим типом.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Yaumen
сообщение Nov 10 2009, 09:13
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213



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

#pragma pack(1)
struct MSGHEADER
{
BYTE ...
BYTE ...
BYTE ...
WORD wParameter
};
#pragma pack()


т.е. смогу ли нормально вычитать WORD переменную:
WORD wVal = pMsg->wParameter
или тоже будут проблемы с выравниванием?
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Nov 10 2009, 09:31
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



Проблем быть не должно - будет медленное обращение по байтам с последующим "склеиванием".
Соответственно, если хочется скорости работы, лучше так не делать.


Да, если сделать, например, так:
Код
int fnc (WORD *ptr);
...
fnc (&pMsg->wParameter);

проблема будет.


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post
koyodza
сообщение Nov 10 2009, 16:10
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 213
Регистрация: 28-02-07
Из: Киев
Пользователь №: 25 744



Цитата(zltigo @ Nov 9 2009, 20:09) *
Не надо рассказывать байки, тем более, которые не помните. 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 (именно в кейле) - этой проблемы не возникало.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Nov 10 2009, 16:22
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(koyodza @ Nov 10 2009, 19:10) *
кейла, ни желания, ни времени на это не было.

Явный чистейшей воды баг Кейла. Подлежит исправлению, что и сделали.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
koyodza
сообщение Feb 9 2010, 19:31
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 213
Регистрация: 28-02-07
Из: Киев
Пользователь №: 25 744



Цитата(zltigo @ Nov 10 2009, 18:22) *
Явный чистейшей воды баг Кейла. Подлежит исправлению, что и сделали.

А как Вы прокомментируете это?
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
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Feb 9 2010, 19:51
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Хм. А какой комментарий вы рассчитываете получить к изложению общеизвестной архитектурной особенности?

"Баг Кейла", как я понимаю, заключался в замене вызова memcpy на LDR/STR при высоком уровне оптимизации без контроля выравнивания.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 12:35
Рейтинг@Mail.ru


Страница сгенерированна за 0.01583 секунд с 7
ELECTRONIX ©2004-2016