Два аргумента для вызова - PullRequest
26 голосов
/ 03 ноября 2010

Почему calloc принимает два аргумента вместо одного, например malloc?

В частности, поскольку нет разницы (или есть?) Между следующими выражениями:

calloc (a, b);
calloc (b, a);
calloc (a * b, 1);
calloc (1, a * b);

почему бы просто не принять общее количество байтов для выделения? В чем смысл этого интерфейса? И почему это не относится к malloc?

Ответы [ 5 ]

7 голосов
/ 03 ноября 2010

Я слышал два [взаимоисключающих] объяснения, почему у него есть два аргумента:

  1. calloc берет на себя ответственность за проверку переполнения при умножении. Если общий размер запрашиваемого блока слишком велик (например, переполнения size_t), calloc возвращает нулевой указатель для указания сбоя. С malloc вы должны следить за переполнением, что многие люди просто забывают сделать. (Хотя история стандартной библиотеки знает примеры calloc реализаций, которые игнорировали переполнение и, следовательно, работали некорректно).

  2. calloc фактически позволяет выделить больше блоков памяти, чем диапазон типа size_t, т. Е. calloc может быть в состоянии выполнить правильное не переполнение большого умножения своих аргументов и выделить блок результирующего размера. По этой причине, поскольку calloc использует два аргумента типа size_t, он может выделить больше блоков, чем когда-либо сможет malloc (поскольку malloc принимает только один аргумент типа size_t).

Я всегда верил, что первое объяснение правильное. Тем не менее, после прочтения некоторых постов здесь на SO у меня есть сомнения.

3 голосов
/ 03 ноября 2010

Я полагаю, что malloc гарантированно возвращает область памяти, которая выровнена в соответствии с самым грубым требованием, которое было бы совместимо с размером, указанным во втором аргументе.Например, если система требует выравнивания 2-х и 4-х байтовых целых чисел, а второй аргумент равен 10, возвращаемый указатель должен быть выровнен по двухбайтовой границе;если бы вторым аргументом было 12, указатель был бы выровнен по четырехбайтовой границе.Я подозреваю, что на практике многие системы будут выравнивать все возвращаемые указатели по максимально возможной требуемой границе, независимо от размера, но я не думаю, что это требуется, за исключением calloc.

0 голосов
/ 03 ноября 2010

Единственное заметное отличие состоит в том, что calloc требуется для инициализации выделенного пространства нулями, тогда как для malloc такой гарантии нет. В противном случае, я думаю, есть две разные функции только по историческим причинам.

0 голосов
/ 03 ноября 2010

Все, что только байты, является относительно новым (то есть эпохой c / Unix) - на многих других архитектурах были записи фиксированного размера.

0 голосов
/ 03 ноября 2010

calloc(x,y) эквивалентно malloc(x*y)

Но calloc делает дополнительные (установка значений на 0 с помощью) memset(block, 0, x*y)

Эта функция предназначена только для удобного прохождения размер элемента и количество элементов , когда в malloc необходимо умножить эти значения для получения необходимого количества байтов, эта функция также проверяет целочисленное переполнение при умножении.

Например, если вы хотите выделить память для 12 целых чисел и хотите сделать что-то с этими целыми числами, и вы должны установить ее значения в 0, используйте calloc(12, sizeof(int))

Но если вы хотите выделить некоторый блок памяти (256 байт)в будущем скопировать в него какую-нибудь строку, тогда memset вам не подходит, тогда лучше использовать malloc(sizeof(char) * 256) или, например, malloc(sizeof(wchar_t) * 256)


void *
calloc (size_t nmemb, size_t lsize)
{
  void *ptr;
  struct __meminfo *info;
  size_t size = lsize * nmemb;

  /* if size overflow occurs, then set errno to ENOMEM and return NULL */
  if (nmemb && lsize != (size / nmemb))
    {
      set_errno (ENOMEM);
      return NULL;
    }

  /* allocate memory */
  ptr = malloc (size);

  /* get pointer to info part of chunk */
  info = __mem2info (ptr);

  /* fill memory with zeros and set __MEM_CALLOC flag */
  memset (ptr, 0, info->size);
  info->flags |= __MEM_CALLOC;

  return ptr;                   /* happy end */
}
...