Скопируйте часть структуры используя memcpy - PullRequest
0 голосов
/ 09 апреля 2020

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

struct A {
  char* baz;
  int foo;
  int bar;
};

void copy(struct A* dst, const struct A* src) {
  dst->baz = malloc(1 + strlen(src->baz));
  strcpy(dst->baz, src->baz);
  memcpy(
    ((void*)dst) + sizeof(char*),
    ((void*)src) + sizeof(char*),
    sizeof(struct A) - sizeof(char*)
  );
}

Это действительно C и не нарушает стандарт? Я знаю, что иногда могут быть некоторые проблемы с выравниванием памяти, я не знаю, относится ли это к этому сценарию.

Второй вопрос - как это сделать, если пропустить более одного элемента, потому что проблемы с заполнением начинают вырасти свои уродливые головы потом

1 Ответ

3 голосов
/ 09 апреля 2020
  • void copy(A* dst, const A* src) недопустимо C, так как вы не определили структуру. Измените значение на typedef struct {...} A;, если вы используете sh для использования этого стиля.
  • strdup недопустимо C (но допустимо в POSIX). Я не рекомендовал бы использовать это для любой цели. Вместо этого используйте malloc + strcpy (или memcpy, если известен размер).
  • dst + sizeof(char*) - нонсенс, поскольку это делает арифметику указателей c на целых структурах. То же самое с src + sizeof(char*).
  • Исправляя эту ошибку, тогда нет никакой гарантии, что (uint8_t*)dst + sizeof(char*) даст адрес члена foo. Компилятор может свободно вставлять отступы в любую часть структуры (кроме самого первого члена).

    Вы можете надежно получить местоположение указанного c члена по offsetof(struct A, foo), что дает вам число байтов от начала структуры до этого указанного c члена.

Разумный способ скопировать указанный c член структуры в противном случае - dst->foo = src->foo;. Нет очевидной причины, по которой ваш код не должен этого делать.

Аналогично, вы можете скопировать только определенные c члены и установить для остальных из них ноль / NULL, используя составной литерал:

*dst = (A){ .foo = src->foo };
...