Копирование структуры в C с назначением вместо memcpy() - программирование
Подтвердить что ты не робот

Копирование структуры в C с назначением вместо memcpy()

До недавнего времени я видел только копирование полей структуры, выполненных с помощью memcpy(). В классах и онлайн-инструкциях копирование содержимого одной структуры в другую обычно выглядит как

struct block *b0 = malloc(sizeof(struct block));
struct block *b1 = malloc(sizeof(struct block));
/* populate fields in *b0 */
memcpy(b1, b0, sizeof *b1); /* copy contents of b0 into b1 */
/* free b0, b1 */

Однако эта задача также может быть выполнена простым присваиванием, заменяющим memcpy().

*b1 = *b0; /* dereferenced struct assignment */

Есть ли веская причина, почему это не так широко используется (по крайней мере, в моем ограниченном опыте)? Являются ли эти два метода-присвоением и memcpy() -эквивалентными, или есть какая-то веская причина использовать memcpy() вообще?

4b9b3361

Ответ 1

Оба метода эквивалентны и выполняют мелкую копию. Это означает, что сама структура копируется, но все ссылки на структуру не копируются.

Что касается того, почему memcpy является более популярным, я не уверен. Старые версии C не поддерживали назначение структуры (хотя это было распространенное расширение уже в 1978 году), поэтому, возможно, стиль memcpy застрял как способ сделать более переносимый код? В любом случае, назначение структуры широко поддерживается в компиляторах ПК, а использование memcpy более подвержено ошибкам (если вы ошиблись, Bad Things, скорее всего, произойдет), и поэтому лучше всего использовать назначение структуры, где это возможно.

Существуют, однако, случаи, когда работает только memcpy. Например:

  • Если вы копируете структуру в или из неустановленного буфера - например, для сохранения/загрузки на/с диска или отправки/получения в сети - вам нужно использовать memcpy, поскольку для назначения структуры требуется как источник, так и предназначенный для правильного выравнивания.
  • Если вы упаковываете дополнительную информацию после структуры, возможно с использованием массива с нулевым элементом, вам нужно использовать memcpy и занести эту дополнительную информацию в поле размера.
  • Если вы копируете массив структур, может быть более эффективным сделать одиночный memcpy, а не цикл и копирование структур по отдельности. Опять же, это не так. Трудно сказать, что реализации memcpy отличаются по своим характеристикам.
  • Некоторые встроенные компиляторы могут не поддерживать назначение структуры. Вероятно, есть и другие более важные вещи, о которых компилятор не поддерживает, конечно.

Обратите также внимание, что хотя в C memcpy и назначение структуры обычно эквивалентны, в С++ memcpy и присвоение структуры не эквивалентны. В общем случае С++ лучше избегать структур memcpy, поскольку назначение структуры может и часто перегружается для выполнения дополнительных функций, таких как глубокие копии или управление счетчиками ссылок.

Ответ 2

Это не может быть точный ответ, который вы ищете.

Я объясняю сценарий, который я встречал.

когда мы используем memcpy(), он побайтно копирует в пункт назначения. поэтому не беспокойтесь о выравнивании данных в архитектуре ARM. Если вы используете оператор =, и любой из адресов не выровнен по 4 байтам, тогда придет ошибка выравнивания.

С сайта Arm:

Указатель на место назначения, которое составляет один байт за предыдущим байтом. Это позволяет продолжить процесс записи with perfect alignment of bytes для конкатенации строк памяти.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0175k/Cihbbjge.html

Ответ 3

Я воскрешаю этот старый вопрос, потому что ответы не объясняют , почему memcpy действительно предпочтительнее.

memcpy является предпочтительным, поскольку он дает понять, что программист хочет скопировать содержимое, а не просто указатели.

В следующем примере два назначения делают две разные вещи:

struct Type *s1,*s2;
*s1=*s2;
s1=s2;

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

Написание его как одного из:

memcpy(s1,s2,sizeof(*s1));
memcpy(s1,s2,sizeof(*s2));
memcpy(s1,s2,sizeof(struct Type));

пусть читатель знает, что целью является копирование контента (за счет проверки безопасности и ограничений по типу).

Некоторые компиляторы (например, gcc) даже вызывают предупреждение о sizeof, когда они сталкиваются с чем-то вроде:

memcpy(s1,s2,sizeof(s1));

Ответ 4

Некоторые люди предпочитают memcpy, потому что то, что они узнали, и они никогда не выяснили, что они могут просто выполнять задание (в древности назначение не было разрешено, но это было давно). Проблемы с выравниванием не беспокоятся, поскольку память, выделенная malloc(), всегда выравнивается правильно. И поскольку компилятор может тривиально перевести это назначение на вызов memcpy, он никогда не будет медленнее или больше кода, чем memcpy. Конечно, есть встроенные системы с плохо устаревшими компиляторами.

Ответ 5

Люди, работающие на встроенной платформе, предпочтут использовать memcopy вместо прямого назначения структуры. В основном, когда вы занимаетесь встроенной платформой, некоторые компиляторы не поддерживают прямое назначение структуры, для чего вам нужно использовать memcopy. если вы работаете на ПК, то в любом случае нет проблем, оба действительны.