Копирование структуры в 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()
вообще?
Ответы
Ответ 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.
если вы работаете на ПК, то в любом случае нет проблем, оба действительны.