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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Скопировать часть массива в переменную 64 бита
IgorAVR2
сообщение Apr 9 2018, 21:54
Сообщение #1


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

Группа: Участник
Сообщений: 153
Регистрация: 29-05-08
Пользователь №: 37 901



Пытаюсь скопировать в переменную uint_64t восемь байт из массива с определённого его индекса. Конструкция такая:
((uint64_t*)&write_key)[0]=(((uint64_t*)(rx_buffer+5))[0]);

write_key - переменная 64 бита.
rx_buffer - байтовый массив.

В строчке пытаюсь копировать с 5 элемента и программа вылетает в Hard Fault.
Если копировать с 0 или 4 элемента то всё ок. Понимаю что что связанно с адресацией но что именно?
Микроконтронтроллер STM32f0, среда IAR. На PC эта же строчка с 5 индексом прокатывает.
Что делаю не так?
Go to the top of the page
 
+Quote Post
_pv
сообщение Apr 9 2018, 22:58
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954



memcpy(&write_key, &rx_buffer[5], 8);
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Apr 10 2018, 04:59
Сообщение #3


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

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



а так?
Код
*((uint64_t *)write_key)) = *((uint64_t *)(rx_buffer+5)));
Go to the top of the page
 
+Quote Post
vadon
сообщение Apr 10 2018, 05:07
Сообщение #4


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

Группа: Свой
Сообщений: 97
Регистрация: 27-07-10
Из: харьков
Пользователь №: 58 632



Цитата
Понимаю что что связанно с адресацией но что именно?


unaligned access

Используйте memcpy
Go to the top of the page
 
+Quote Post
IgorAVR2
сообщение Apr 10 2018, 09:57
Сообщение #5


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

Группа: Участник
Сообщений: 153
Регистрация: 29-05-08
Пользователь №: 37 901



Цитата(Jenya7 @ Apr 10 2018, 07:59) *
а так?
Код
*((uint64_t *)write_key)) = *((uint64_t *)(rx_buffer+5)));

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


Да, memcopy то я туда и поставил, только memcopy побайтно копирует, а хотелось по словам.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 10 2018, 10:32
Сообщение #6


Гуру
******

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



Цитата(IgorAVR2 @ Apr 10 2018, 12:57) *
Да, memcopy то я туда и поставил, только memcopy побайтно копирует, а хотелось по словам.

memcpy копирует не побайтно, а оптимально с учетом выравнивания. Довольно сложная процедура.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 10 2018, 11:00
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Jenya7 @ Apr 10 2018, 07:59) *
а так?
Код
*((uint64_t *)write_key)) = *((uint64_t *)(rx_buffer+5)));

Прежде чем что-то советовать надо научиться читать и понимать то, что пишут. Чтобы не писать ерунду.
Из контекста исходного сообщения автора видно, что write_key - это не указатель, а переменная в которую нужно записать. Это во-первых. А во-вторых - читайте про невыровненный доступ в Cortex-M.

Цитата(IgorAVR2 @ Apr 10 2018, 12:57) *
Так тоже не прокатило. Туда же в ошибку и улетает.

Для IAR (а может и других компиляторов):
Код
typedef unsigned long long u64;
typedef __packed u64 u64p8;
*(u64p8 *)&write_key = *(u64p8 *)&rx_buffer[5];
...и уже сам компилятор решит какие команды использовать.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Apr 10 2018, 11:27
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



А можно просто выровнять буфер если считываемые слова выравнены относительно друг друга. Если нет, делайте memcpy - так правильней всего и компилятор оптимизирует вызовы обычно.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 10 2018, 11:34
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Kabdim @ Apr 10 2018, 14:27) *
А можно просто выровнять буфер если считываемые слова выравнены относительно друг друга. Если нет, делайте memcpy - так правильней всего и компилятор оптимизирует вызовы обычно.

В случае с __packed u64 если в buildtime известно, что ((uint)(rx_buffer+5) & 3) == 0, то компилятор для чтения сгенерит одну команду LDRD (если она есть в данном ядре, ну или две LDR). А про memcpy() я совсем не уверен, что получится так же оптимально.
Go to the top of the page
 
+Quote Post
IgorAVR2
сообщение Apr 10 2018, 11:43
Сообщение #10


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

Группа: Участник
Сообщений: 153
Регистрация: 29-05-08
Пользователь №: 37 901



Цитата(jcxz @ Apr 10 2018, 14:00) *
Код
typedef unsigned long long u64;
typedef __packed u64 u64p8;
*(u64p8 *)&write_key = *(u64p8 *)&rx_buffer[5];
...и уже сам компилятор решит какие команды использовать.


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

А если делать через memcpy, как советует Kabdim, то компилятор разве не будет побайтно копировать?

Пока писал вопрос уже ответили - и я вот сомневаюсь насчёт memcpy.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Apr 10 2018, 11:44
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Зря не верите, все современные компиляторы насколько я знаю оптимизируют это в релизбилде. Другое дело что они не всегда по коду могут сказать что ((uint)(rx_buffer+5) & 3) == 0. Но в этом случае ни один, ни второй метод не будут соптимизирован.
Можно сделать аля:
Код
uint64_t inner_buffer[x];
uint8_t *rx_buffer = static_cast<uint8_t*>(&inner_buffer[0]) + 3;

И продолжать жечь в духе первого поста. Только возможно еще и с индексами, а не с адресной арифметикой.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 10 2018, 12:04
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(IgorAVR2 @ Apr 10 2018, 14:43) *
так как переменные не выровнены в памяти, то он всё рано будет копировать побайтно.

Нет, если компилятор на этапе сборки кода будет знать, что ((uint)(rx_buffer+5) & 3) == 0, то он использует LDRD или пару LDR. Если нет, но ((uint)(rx_buffer+5) & 1) == 0, то он может использовать LDRH,LDR,LDRH. Если на этапе сборки кода значение rx_buffer неизвестно, то будет использовать побайтный доступ.
Go to the top of the page
 
+Quote Post
IgorAVR2
сообщение Apr 10 2018, 12:52
Сообщение #13


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

Группа: Участник
Сообщений: 153
Регистрация: 29-05-08
Пользователь №: 37 901



Понял, спасибо!
Go to the top of the page
 
+Quote Post
IgorAVR2
сообщение Apr 10 2018, 14:02
Сообщение #14


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

Группа: Участник
Сообщений: 153
Регистрация: 29-05-08
Пользователь №: 37 901



Вычитал в в аналогичном топике, что оказывается STM32f4 об этом думать не нужно. Вот и у меня видимо до этого так раньше работало в других проектах.
https://electronix.ru/forum/lofiversion/ind...hp/t140216.html
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 10 2018, 14:15
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(IgorAVR2 @ Apr 10 2018, 17:02) *
Вычитал в в аналогичном топике, что оказывается STM32f4 об этом думать не нужно. Вот и у меня видимо до этого так раньше работало в других проектах.

Нет, не поэтому. Не нужно для операций LDR/STR - только они поддерживают невыровненный доступ на M3/M4. А если Вы пишете тип u64, то для работы с таким типом компилятор может применить LDRD/STRD, а эти команды не поддерживают невыровненный доступ даже в M4.
Хотя может какой-то конкретный, не очень оптимизирующий компилятор, вместо одной LDRD, может применить пару LDR, тогда прокатит.
Но чтобы не гадать, хорошим тоном является явное указание невыровненности переменной (__packed), тогда компилятор сам решит как нужно работать с данной переменной на данном ядре. И не будет сюрпризов при переносе кода на другое ядро.

PS: Да и учиться нужно не по "топикам" где могут нести какую угодно чушь, а по мануалам на ядро. Там всё разжёвано.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 29th June 2025 - 01:45
Рейтинг@Mail.ru


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