Подтвердить что ты не робот

Почему задано значение возвращаемого значения malloc (0)?

ISO/IEC 9899: TC2 (т.е. стандарт C99), §7.20.3:

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

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

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

4b9b3361

Ответ 1

Обоснование 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 */
} 

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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