Почему возвращаемое значение malloc (0) определяется реализацией? - PullRequest
16 голосов
/ 21 марта 2011

ИСО / МЭК 9899: TC2 (то есть стандарт C99), §7.20.3 гласит:

Если размер запрошенного пространства равен нулю, поведение определяется реализацией: либовозвращается нулевой указатель, или поведение такое, как если бы размер был некоторым ненулевым значением, за исключением того, что возвращенный указатель не должен использоваться для доступа к объекту.

Другими словами, malloc (0) можетлибо верните NULL, либо верный указатель, который я не могу разыменовать.

В чем причина такого поведения?И не проще ли определить, что malloc (0) ведет к UB?

Ответы [ 3 ]

15 голосов
/ 21 марта 2011

Обоснование C99 (ссылка в формате PDF) обсуждает функции управления памятью (из C99 7.20.3) и объясняет:

Обработка нулевых указателей и запросов на выделение нулевой длины в определении этих функций частично была обусловлена ​​желанием поддержать эту парадигму:

OBJ * p; // pointer to a variable list of OBJs
    /* initial allocation */
p = (OBJ *) calloc(0, sizeof(OBJ)); 
    /* ... */
    /* reallocations until size settles */
while(1) { 
    p = (OBJ *) realloc((void *)p, c * sizeof(OBJ)); 
      /* change value of c or break out of loop */
} 

Сообщается, что этот стиль кодирования, не обязательно одобренный Комитетом, широко используется.

Некоторые реализации возвращали ненулевые значения для запросов на выделение нулевых байтов.
Хотя эта стратегия имеет теоретическое преимущество, заключающаяся в различении «ничего» и «нуля» (нераспределенный указатель и указатель на пространство нулевой длины), она имеет более убедительный теоретический недостаток, заключающийся в необходимости концепции объекта нулевой длины.

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

Комитет С89 решил не принимать идею объектов нулевой длины. Распределение поэтому функции могут возвращать нулевой указатель для запроса на выделение нулевых байтов. Обратите внимание, что это лечение не исключает изложенную выше парадигму.

ТИХОЕ ИЗМЕНЕНИЕ В C89 : Программа, которая опирается на запросы выделения нулевого размера, возвращающие ненулевой указатель, будет вести себя по-другому.

9 голосов
/ 21 марта 2011

Потому что выделение 0 байтов может иметь смысл. Например, когда вы выделяете массив с неизвестным количеством элементов. UB допускает сбой программы, тогда как при текущем поведении вы можете безопасно выделить numberOfItems * itemSize байтов.

Логика следующая: если вы запрашиваете 0 байтов, вы получаете указатель обратно. Конечно, вы не должны разыменовывать его, так как это получило бы доступ к 0-му байту (который вы не выделили). Но вы можете безопасно освободить память впоследствии. Так что вам не нужно указывать 0 как особый случай.

Это было о том, почему бы не определить malloc(0) как UB. О решении не определять результат строго (NULL против уникального указателя на пустое место) см. Ответ Джеймса. (Короче говоря: оба подхода имеют свои преимущества и недостатки. Идея возврата уникального ненулевого указателя является более убедительной, но требует более концептуальной работы и увеличивает нагрузку на разработчиков.)

4 голосов
/ 21 марта 2011

Создание malloc(0) результата в UB будет намного хуже.В нынешнем виде вам не нужно заботиться о том, что происходит, когда размер равен нулю, если вы последовательны в вызове free.

Проблема в том, что некоторые существующие реализации выделяют указатель для malloc(0), некоторые возвращают нулевые указатели, и почти все они непреклонны в том, чтобы придерживаться своего поведения, потому что те же самые люди, которые написали реализации, написали много плохого, непереносимого программного обеспечения, которое использует их выбранное поведение (GNU является одним из худшихпреступники в этой области).Таким образом, стандарт застрял, позволяя обоим моделям поддерживать их всех счастливыми.

...