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

 
 
 
Reply to this topicStart new topic
> memcpy(void * __restrict , const void * __restrict, size_t );
pitt
сообщение Mar 1 2013, 23:33
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



имеется
Код
typedef struct {
  uint8_t  type;
  uint16_t len;
  uint8_t *info;
} pack_s;
...
pack_s *p_src, *p_dst;
uint8_t info[SIZE];
// оба p уже установлены к этому моменту, причем, p_dst, где-то внутри info, поэтому стоит адрес
// учтите, логика, проверена и работает на х86
memcpy(&p_dst->data, p_src->data, p_src->len);

Так как пакеты создаются извне и размещается в памяти последовательно, т.е. начало пакета может случиться по любому адресу, необходимо использовать, например, #pragma __pack(1), но тогда идет ошибка компиляции из-за __restrict. Прошу заметить, оптимизация отключена, как и С99, т.е. ANSI-C без прибамбасов. Если убрать прагму, то ARMCC НЕПОНЯТНО ЗАЧЕМ выравнивает поинтер на границу 32-битного слова и, по-сему, портит структуру. Не желаю вместо memcpy использовать свой С-код.
Вопросы к публике: есть ли у кого инлайн ассемблер для менее привередлигого memcpy или другие разумные предложения.

PS: НЕПОНЯТНО ЗАЧЕМ употребил потому, что НЕ понимаю как выравнивание может играть роль в случае указателя, который может быть установлен на любой адрес.

Спасибо.


--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post
Alex A. Mihaylov
сообщение Mar 2 2013, 05:08
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 63
Регистрация: 15-11-10
Из: Санкт-Петербург
Пользователь №: 60 892



Цитата(pitt @ Mar 2 2013, 03:33) *
Так как пакеты создаются извне и размещается в памяти последовательно, т.е. начало пакета может случиться по любому адресу, необходимо использовать, например, #pragma __pack(1)


Очень сомнительное утверждение. Продумайте логику работы програмы. А самое главное - собирая в памяти последовательно пакеты вы наверняка порождаете ненужную энтропию и сильно ломаете устойчивость кода к нештатным ситуациям. На самом деле выравнивание позволяет чуть быстрее работать с данными. При этом выравнивание самих структур практически никогда не мешает, а вот выравнивание полей структуры... Но судя по коду это не Ваш случай.

Цитата(pitt @ Mar 2 2013, 03:33) *
Вопросы к публике: есть ли у кого инлайн ассемблер для менее привередлигого memcpy или другие разумные предложения.


Хм... Категорически не советую опускаться до ассемблера. Нагородите. По факту - ну напишите свой не привередливый memcpy. Примеров реализации разной степени оптимизированности навалом. А вообще почитайте внимательно мануал на тему memcpy. Ответ на Ваш вопрос там. И сдается мне, что дело тут не в __restrict, а в const.

Кстати, а какой ARM? Старые ядра (класса ARM7TDMI) предуют выравненного обращения к словам и двойным словам иначе ловят data abort.

Сообщение отредактировал Alex A. Mihaylov - Mar 2 2013, 05:08
Go to the top of the page
 
+Quote Post
kan35
сообщение Mar 2 2013, 06:05
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Цитата(pitt @ Mar 2 2013, 03:33) *
НЕПОНЯТНО ЗАЧЕМ употребил потому, что НЕ понимаю как выравнивание может играть роль в случае указателя, который может быть установлен на любой адрес.

Конечно вы не понимаете, так как похоже не читали описание этой дериктивы. Она влияет на стрктуры, юнионы для того, чтобы данные размещались в них с выравниванием. Простой пример: 8 битный компилятор как правило по умолчанию размещает данные с выравниванием на 1 байт, а 32 битный - на 4 байта, в итоге структуры в одном компиляторы будут одного размера, а в другом - другого, и если передавать данные структурами, например в USB или TCP или в любом вашем протоколе, или сохранять на одном а открывать на другом, то конечно попадания байт-в-байт не будет. Для этого и применяется эта прагма.
Если же эти структуры используются внутри одного приложения и ни кем больше, то pack как правило вообще не нужен.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 2 2013, 11:06
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(pitt @ Mar 2 2013, 00:33) *
// учтите, логика, проверена и работает на х86
memcpy(&p_dst->data, p_src->data, p_src->len);

Работает? Это же просто каша в коде написана!
1. Где поле data в в структуре типа pack_s? Может, имеется ввиду ->info?
2. Если поле info есть указатель, почему первый параметр по ссылке (с &)?

Мои догадки:
1. info[SIZE] есть, видимо, какой-то общий буфер, в котором где-то "вложена" структура pack_s, которая, похоже, представляет собой блок данных, предваренный его типом и длиной. В этом случае структуру следует записать как
Код
typedef __packed struct {
  uint8_t  type;
  uint16_t len;
  uint8_t   data[1];
} pack_s;

понимая, что data[1] на самом деле есть сам буфер переменной длины, а не указатель на куда-то еще.

2. Возможен и другой вариант: структура pack_s в виде от автора есть просто некий универсальный описатель, который, будучи наложен на последовательность байт, выглядит как я описал выше, а будучи использован где-то внутри кода, - действительно не содержит данные, а указывает на еще один буфер с ними посредством *info. Это подозрение следует из memcpy(&p_dst->data, p_src->data, p_src->len), где, к слову, вместо data должно быть info, а имя для info[SIZE] есть просто катастрофа с бодуна, и должно быть выбрано иным. Ну тогда уж надо бы написать:

Код
#pragma anon_unions
typedef __packed struct {
  uint8_t  type;
  uint16_t len;
  __packed uinon {
    uint8_t   data[1];
    uint8_t  *info;
  }
} pack_s;
...
memcpy(p_dst->data, p_src->info, p_src->len);
// или
memcpy(p_dst->info, p_src->data, p_src->len);

Я написал два варианта memcpy, т.к. это автор знает, что на что у него "положено", пусть уточнит.

Сообщение отредактировал KnightIgor - Mar 2 2013, 11:09
Go to the top of the page
 
+Quote Post
kan35
сообщение Mar 2 2013, 11:47
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Функции memcpy работает с данными выровненными на байт. Не важно какой процессор, и какое там выравнивание в нем, все эти проблемы решены на уровне С компилятора для данного процессора. И потому не надо писать другие memcpy.
Go to the top of the page
 
+Quote Post
pitt
сообщение Mar 2 2013, 13:39
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



Cortex-M3
Да, действительно ->info.
Код
void c_copy (void *d, const void *s, uint16_t len) {
  uint16_t i;

  for (i = 0; i < len; i++} *d++ = *s++;
}


Не создает никаких проблем.


--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 2 2013, 15:13
Сообщение #7


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(pitt @ Mar 2 2013, 14:39) *
Код
void c_copy (void *d, const void *s, uint16_t len) {
  uint16_t i;
  for (i = 0; i < len; i++} *d++ = *s++;
}

Не создает никаких проблем.

Проблема №1 - закрывающая фигурная скобка вместо круглой в for
Проблема №2 "error: #852: expression must be a pointer to a complete object type", причем два раза: вот у Вас указатель void, так откуда ++ будет знать, на сколько двигать указатель?

Приведенный выше код - это расчленёнка, как криминалисты говорят.
Go to the top of the page
 
+Quote Post
pitt
сообщение Mar 2 2013, 15:23
Сообщение #8


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



Код
void c_copy (void *d, const void *s, uint16_t len) {
  uint16_t i;
  uint8_t * dst, *src;

  dst = d;
  src = s;
  for (i = 0; i < len; i++) *dst++ = *src++;
}




--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 2 2013, 17:22
Сообщение #9


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(pitt @ Mar 2 2013, 16:23) *

Так memcpy() отлично проглатывает параметры (void *d, const void *s, uint16_t len), без ошибок. Так что не нужно множить сущности.
Go to the top of the page
 
+Quote Post
pitt
сообщение Mar 2 2013, 20:45
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



Код
/* string.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.11 */
/* Copyright (C) Codemist Ltd., 1988-1993.                        */
/* Copyright 1991-1993 ARM Limited. All rights reserved.          */
/* version 0.04 */

/*
* RCS $Revision: 137748 $
* Checkin $Date: 2008-09-11 17:34:24 +0100 (Thu, 11 Sep 2008) $
*/
........
extern _ARMABI void *memcpy(void * __restrict /*s1*/,
                    const void * __restrict /*s2*/, size_t /*n*/) __attribute__((__nonnull__(1,2)));
   /*
    * copies n characters from the object pointed to by s2 into the object
    * pointed to by s1. If copying takes place between objects that overlap,
    * the behaviour is undefined.
    * Returns: the value of s1.
    */
........

Цитата(KnightIgor @ Mar 2 2013, 12:22) *
Так что не нужно множить сущности.




--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post
PheeL
сообщение Mar 3 2013, 07:45
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 32
Регистрация: 24-11-07
Пользователь №: 32 633



Цитата(pitt @ Mar 3 2013, 00:45) *
Код
        * If copying takes place between objects that overlap,
    * the behaviour is undefined.
    * Returns: the value of s1.
    */
........

Конкретно для этого случая есть в наличие тоже стандартная memove();
Go to the top of the page
 
+Quote Post
pitt
сообщение Mar 3 2013, 13:07
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



Цитата(PheeL @ Mar 3 2013, 02:45) *
Конкретно для этого случая есть в наличие тоже стандартная memove();

Нету перекрытия, конкретно не тот случай.
Повторяю: проблема в том, что __restrict в определении memcpy не компилируется, когда включен __packed(1) , а без него, компилятор выравнивает структуру, изменяя ее размер, что недопустимо. Вопрос в том, что может ли кто предложить решение эффективней C-copy().
Спасибо.


--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post

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

 


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


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