Перейти к содержанию
    

memcpy(void * __restrict , const void * __restrict, size_t );

имеется

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

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так как пакеты создаются извне и размещается в памяти последовательно, т.е. начало пакета может случиться по любому адресу, необходимо использовать, например, #pragma __pack(1)

 

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

 

Вопросы к публике: есть ли у кого инлайн ассемблер для менее привередлигого memcpy или другие разумные предложения.

 

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

 

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

Изменено пользователем Alex A. Mihaylov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Конечно вы не понимаете, так как похоже не читали описание этой дериктивы. Она влияет на стрктуры, юнионы для того, чтобы данные размещались в них с выравниванием. Простой пример: 8 битный компилятор как правило по умолчанию размещает данные с выравниванием на 1 байт, а 32 битный - на 4 байта, в итоге структуры в одном компиляторы будут одного размера, а в другом - другого, и если передавать данные структурами, например в USB или TCP или в любом вашем протоколе, или сохранять на одном а открывать на другом, то конечно попадания байт-в-байт не будет. Для этого и применяется эта прагма.

Если же эти структуры используются внутри одного приложения и ни кем больше, то pack как правило вообще не нужен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

// учтите, логика, проверена и работает на х86

memcpy(&p_dst->data, p_src->data, p_src->len);

Работает? Это же просто каша в коде написана!

1. Где поле data в в структуре типа pack_s? Может, имеется ввиду ->info?

2. Если поле info есть указатель, почему первый параметр по ссылке (с &)?

 

Мои догадки:

1. info есть, видимо, какой-то общий буфер, в котором где-то "вложена" структура 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 есть просто катастрофа с бодуна, и должно быть выбрано иным. Ну тогда уж надо бы написать:

 

#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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Функции memcpy работает с данными выровненными на байт. Не важно какой процессор, и какое там выравнивание в нем, все эти проблемы решены на уровне С компилятора для данного процессора. И потому не надо писать другие memcpy.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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++;
}

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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, так откуда ++ будет знать, на сколько двигать указатель?

 

Приведенный выше код - это расчленёнка, как криминалисты говорят.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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++;
}

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так memcpy() отлично проглатывает параметры (void *d, const void *s, uint16_t len), без ошибок. Так что не нужно множить сущности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

/* 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.
    */
........

Так что не нужно множить сущности.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

        * If copying takes place between objects that overlap,
    * the behaviour is undefined.
    * Returns: the value of s1.
    */
........

Конкретно для этого случая есть в наличие тоже стандартная memove();

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Конкретно для этого случая есть в наличие тоже стандартная memove();

Нету перекрытия, конкретно не тот случай.

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

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...