Функция "memdup" в C?

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

struct myStruct *foo = malloc(sizeof(struct myStruct));
fill_myStruct(foo);

struct myStruct *bar = memdup(foo, sizeof(struct myStruct));
// bar is now a reference to a new, appropriately sized block of memory,
//   the contents of which are the same as the contents of foo

Поэтому мой вопрос трижды:

  • Есть ли какая-то стандартная библиотечная функция, о которой я не знаю?
  • Если нет, существует ли сжатый и предпочтительно стандартный способ сделать это без явных вызовов malloc и memcpy?
  • Почему C включает strdup, но не memdup?

Ответы

Ответ 1

Создание копии произвольной структуры памяти не так прямо, как копирование строки. Как вы должны обрабатывать случай, когда структура содержит указатели на другие структуры (например, строки), например? Что значит "дублировать" такую ​​структуру? На этот вопрос нет ни одного правильного ответа, в отличие от случая с строкой. В этом случае, вероятно, лучше просто позволить разработчику приложения создать механизм для создания копии структуры в соответствии с их вариантами использования, а не путать проблему, притворившись, что существует канонический способ ее обработки.

Ответ 2

Вы можете реализовать его с простой функцией:

void* memdup(const void* mem, size_t size) { 
   void* out = malloc(size);

   if(out != NULL)
       memcpy(out, mem, size);

   return out;
}

Ответ 3

В GNU Gnulib есть void *xmemdup (void const *p, size_t s). xalloc.h.

Обратите внимание, что он вызывает xalloc_die в случае нехватки памяти.

Ответ 4

Вероятно, вы просто хотите определить memdup() самостоятельно, а затем просто используйте его в своем коде, как уже было предложено. Моя версия функции следует.

void *
memdup(const void *src, size_t n)
{
    void *dest;

    dest = malloc(n);
    if (dest == NULL)
            return NULL;

    return memcpy(dest, src, n);
}

Что касается обсуждения того, является ли memdup() слишком тривиальным или даже избыточным, я так не думаю. Это так полезно для копирования структур в вашем коде. Стандарты ANSI/ISO и POSIX для стандартной библиотеки C содержат так много удобных функций, но, к сожалению, не этот.

Пример: повторная реализация strdup() с помощью memdup().

char *
strdup(const char *src)
{
    return memdup(src, strlen(src) + 1);
}

Пример: использование memdup() для дублирования объекта.

int
some_function(const struct some_struct *some_const_data)
{
    struct some_struct *my_mutable_copy;

    if ((my_mutable_copy = memdup(some_const_data)) == NULL)
        return -1;

    ...

    return 0;
}

Ответ 5

Функция strdup считывает и копирует до нулевого значения в строке с нулевым завершением. Однако нормальные данные не имеют таких разделителей, поэтому вам нужно указать длину данных для копирования.