Два аргумента для calloc
Почему calloc
принимает два аргумента вместо одного типа malloc
?
В частности, поскольку между выражениями (или есть?) нет разницы между следующими выражениями:
calloc (a, b);
calloc (b, a);
calloc (a * b, 1);
calloc (1, a * b);
Почему бы просто не принять общее количество байтов для распределения? В чем смысл этого интерфейса? И почему это не относится к malloc?
Ответы
Ответ 1
Я слышал два [взаимоисключающих] объяснения, почему у него есть два аргумента:
-
calloc
берет на себя ответственность за проверку переполнения при умножении. Если общий размер запрошенного блока слишком велик (например, переполнение size_t
), calloc
возвращает пустой указатель, указывающий на сбой. С помощью malloc
вы должны следить за переполнением себя, что многие люди просто забывают делать. (Хотя история стандартной библиотеки знает примеры реализаций calloc
, которые игнорировали переполнение и, следовательно, работали некорректно).
-
calloc
фактически позволяет выделять более крупные блоки памяти, чем диапазон типа size_t
, т.е. calloc
может быть способен выполнять правильное непереполняющее большое умножение своих аргументов и выделять блок от полученного размера. По этой причине, поскольку calloc
использует два аргумента типа size_t
, он может выделять более крупные блоки, чем malloc
когда-либо сможет (поскольку malloc
принимает только один аргумент типа size_t
).
Я всегда считал, что первое объяснение является правильным. Однако после прочтения некоторых сообщений здесь, на SO, у меня есть свои сомнения.
Ответ 2
Я считаю, что malloc гарантированно вернет область памяти, которая выровнена в соответствии с самым грубым требованием, которое будет совместимо с размером, указанным вторым аргументом. Например, если система требует выравнивания 2 и 4 байтовых целых чисел, а второй аргумент равен 10, возвращаемый указатель должен быть выровнен на двухбайтовой границе; если второй аргумент равен 12, указатель будет выровнен на четырехбайтовой границе. Я подозреваю, что на практике многие системы будут выровнять все возвращенные указатели с наибольшей возможной границей независимо от размера, но я не думаю, что это необходимо, кроме calloc.
Ответ 3
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 */
}
Ответ 4
Единственная заметная разница заключается в том, что calloc
требуется для инициализации выделенного пространства для нулей, пока нет такой гарантии с malloc
. В противном случае, я думаю, есть две разные функции только по историческим причинам.
Ответ 5
Все просто байты - это относительно новое (например, c/Unix) изобретение - на многих других архитектурах были фиксированные записи.