Я использую эту функцию для копирования некоторых значений из одного массива в другой массив:

void *copy_array(const void *src, void *dest, uint8 pos, uint8 len, uint8 elemsize)
{
   const unsigned char *csrc = src;

   memcpy(dest, csrc + (pos * elemsize), len * elemsize);
}

Есть ли аналогичный способ сделать это без использования арифметики указателя? MISRA предлагает избегать арифметики указателей.

1
JohnDoe 25 Мар 2020 в 18:45
3
Нет веской причины избегать арифметики указателей в этом коде, если он будет использоваться в производственном программном обеспечении. Это упражнение для класса? Если да, то какова фактическая постановка проблемы? Существуют разные концептуальные уровни, на которых можно рассматривать «арифметику указателей» — явное выражение в исходном коде C, неявное выражение, такое как ссылка на массив, и на машинном уровне. На последнем уровне невозможно избежать арифметики указателей, так как адрес памяти необходим для загрузки данных и, следовательно, он должен вычисляться. В чем настоящая проблема?
 – 
Eric Postpischil
25 Мар 2020 в 18:58
2
Ответ зависит от требуемого уровня «подобия» ;-) Если вам нужно соответствие мисре, я бы рекомендовал избегать принятия или возврата void*, если это возможно.
 – 
Hulk
25 Мар 2020 в 19:03
3
IMO, основная проблема здесь в первую очередь заключается в наличии указателей void.
 – 
Jabberwocky
25 Мар 2020 в 19:15
2
Код C не может быть типобезопасным И универсальным, поэтому вам нужно выбрать один - и если вам нужно соответствие MISRA, выбор не за вами - печальный ответ заключается в том, что вы не можете реализовать эту вспомогательную функцию безопасным способом.
 – 
Hulk
25 Мар 2020 в 19:19
4
По сути, правила MISRA не хотят, чтобы вы возились с арифметикой указателей, потому что вы можете все испортить. Но этой подпрограмме передаются только адреса, размеры элементов и индексы элементов. Это означает, что он не может выполнять свою работу без вычисления адресов (прямо или косвенно), и любой, кто вызывает его, уже подвергается риску, которого MISRA хочет избежать, путем декомпозиции своих высокоуровневых объектов (таких как массив известного типа) на части, такие как размеры элементов. Лучшее, что вы можете сделать в этой программе, это const uint8 (*x)[elemsize] = src; memcpy(dest, &x[pos], len * sizeof *x);.
 – 
Eric Postpischil
25 Мар 2020 в 20:00

1 ответ

Для соответствия требованиям MISRA просто выполните memcpy(dest, &csrc[pos * elemsize], len * elemsize);.

Хотя я не совсем понимаю, зачем вам нужна функция для этого, вместо того, чтобы просто вызывать memcpy напрямую. Как упоминалось в комментариях, MISRA не одобряет использование пустых указателей через рекомендательные правила, поскольку критически важное программное обеспечение должно быть детерминированным, а не общим.

Кроме того, len * elemsize довольно сомнительна, так как это ограничило бы функцию массивами размером не более 255 байт.

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

#define copy_array(src, dst, pos, len, elemsize) \
  memcpy((dst), &(src)[(pos)*(elemsize)], (len)*(elemsize))
1
Lundin 26 Мар 2020 в 11:51