Почему calloc принимает два аргумента, а malloc — только один?

IMO одного достаточно, почему calloc требуется разделить его на два аргумента?


person x86    schedule 24.09.2011    source источник
comment
Потому что какой-то программист создал его таким и таким он навсегда остался...   -  person    schedule 24.09.2011
comment
Если вам это не нравится, #define calloc(x) (calloc)(x, 1) должно работать.   -  person Chris Lutz    schedule 24.09.2011
comment
@Chris, использующий препроцессор для переопределения malloc или семейства, кажется очень плохой идеей (за исключением, возможно, отладки распределения памяти).   -  person ssube    schedule 24.09.2011
comment
Поскольку calloc() требует двух аргументов; один для определения количества элементов, один для определения размера элементов. Кстати, calloc() очищает всю выделенную память до нуля. Почему это проблема?   -  person user732933    schedule 24.09.2011
comment
@peachykeen - Это так. Технически это UB в стандарте, хотя на практике было бы безумием не работать. Тем не менее, мой комментарий на самом деле не должен был быть хорошим советом.   -  person Chris Lutz    schedule 24.09.2011
comment
Теоретически calloc имеет преимущество в том, что может выделять более SIZE_MAX байтов; хотя некоторые распространенные реализации перепутали это и умножили аргументы с точностью size_t   -  person M.M    schedule 13.03.2015


Ответы (2)


Я предполагаю, что это, вероятно, история и предшествует временам, когда C имел прототипы для функций. В те времена без прототипа аргументы в основном должны были быть int, typedef size_t, вероятно, еще даже не были изобретены. Но тогда INTMAX — это самый большой кусок, который вы можете выделить с помощью malloc, и разделение его на две части просто дает вам больше гибкости и позволяет вам выделять действительно большие массивы. Даже в то время существовали методы получения больших страниц из системы, которые по умолчанию обнулялись, поэтому эффективность была не такой большой проблемой для calloc, чем для malloc.

В настоящее время, когда под рукой есть size_t и прототип функции, это просто ежедневное напоминание о богатой истории C.

person Jens Gustedt    schedule 24.09.2011
comment
Это вообще не отвечает на вопрос. Ширина используемого целочисленного типа совершенно не имеет отношения к этому вопросу. - person Jeff Hammond; 20.04.2015
comment
@Джефф, можешь объяснить? Я не говорю, что ширина целочисленного типа, используемого сегодня, имеет какое-то отношение к этому. Я говорю, что на момент создания интерфейса это могло быть проблемой. - person Jens Gustedt; 20.04.2015
comment
Я возражаю против предположения, что это для действительно больших массивов. Использование двух аргументов вместо одного — плохой дизайн API. И почему кто-то хочет calloc указатель, который они не могли впоследствии realloc произвольно или на котором они не могли использовать, например. memset или memcpy? Не стесняйтесь раздражаться на мою педантичность, но было бы разумно сказать что-нибудь о возврате sizeof() без знака и выделении массивов немного больше, чем INT_MAX. - person Jeff Hammond; 20.04.2015
comment
Кроме того, у раннего C (K&R) были прототипы — они просто не требовались для аргументов, отличных от int. И long int существовал, так что было решение более крупной проблемы, чем int, даже если size_t еще не было. - person Jeff Hammond; 20.04.2015
comment
@Jeff, AFAIR, спецификация параметров K&R в старом стиле для типов, отличных от int, не предоставляет прототипов. Они были представлены в C89. Что касается несоответствия с malloc и realloc, вы, вероятно, правы, и это странный выбор интерфейса. Но, к сожалению, это одна из немногих вещей, которые остались и с которыми мы сейчас застряли. - person Jens Gustedt; 20.04.2015
comment
@Jeff, AFAIR, спецификация параметров K&R в старом стиле для типов, отличных от int, не предоставляет прототипов. Они были представлены в C89. Что касается несоответствия с malloc и realloc, вы, вероятно, правы, и это странный выбор интерфейса. Но, к сожалению, это одна из немногих вещей, которые остались и с которыми мы сейчас застряли. - person Jens Gustedt; 20.04.2015

Имена параметров документируют это достаточно хорошо:

void *malloc(size_t size);
void *calloc(size_t nelem, size_t elsize);

Последняя форма позволяет аккуратно размещать массивы, указывая количество элементов и размер элемента. Такого же поведения можно добиться с помощью malloc путем умножения.

Однако calloc также инициализирует выделенную память значением 0. malloc не выполняет инициализацию, поэтому значение не определено. malloc теоретически может быть быстрее из-за того, что не выделяется вся память; это можно заметить только при больших количествах.

В этом вопросе предполагается, что calloc — это clear-alloc, а malloc — память-аллок.

person ssube    schedule 24.09.2011
comment
Еще одним преимуществом двух аргументов является возможность проверки переполнения, что обычно сложно (и редко выполняется) с malloc (хотя, если вы выделяете объекты такого размера, который может переполниться, вы можете делать это неправильно). - person Chris Lutz; 24.09.2011
comment
@Chris: Может быть, нам нужен cccalloc, который принимает 6 аргументов и выделяет a*b + c*d + e*f байта с проверкой переполнения для всех подвыражений... ;-) - person R.. GitHub STOP HELPING ICE; 24.09.2011
comment
Не думаю, что это ответ на вопрос. Это не спрашивает, как они работают (тогда это будет просто дублировано и должно быть закрыто). Он требует обоснования разделения аргумента на две части вместо одного общего размера, как для malloc. - person Jens Gustedt; 24.09.2011
comment
@Jens: Они делают разные вещи, в частности calloc очищают память. Это, по крайней мере, хорошая часть ответа. - person ssube; 24.09.2011
comment
@peachykeen, нет, тот факт, что они делают разные вещи, не имеет ничего общего с тем, что одному требуется один аргумент, а другому - два. Оба используют свои аргументы для определения общего размера памяти, которая должна быть выделена. - person Jens Gustedt; 24.09.2011
comment
@R.. - Из имени и этих параметров очевидно, что он должен выделять a * b + (c + d) * e + f пространство. ;) - person Chris Lutz; 25.09.2011
comment
@Chris: Как вы, наверное, понимаете, я математик. Нам не нравятся многословные имена переменных. :-) - person R.. GitHub STOP HELPING ICE; 25.09.2011
comment
@R.. - У меня тоже есть привычка использовать такие имена. char *s, size_t l примерно так же ясно, как я иногда делаю вещи. - person Chris Lutz; 25.09.2011
comment
Да, это мои любимые, но некоторые люди убьют вас за использование l ever только потому, что их шрифты отстой. ;-) Мне кажется, что как только ваша функция станет настолько большой, что однобуквенные имена переменных сбивают с толку, вероятно, пришло время реорганизовать... - person R.. GitHub STOP HELPING ICE; 25.09.2011
comment
calloc может быть быстрее, чем malloc+memset ком/вопросы/2688466/ - person phuclv; 18.04.2014