Каков переносимый способ проверить, не удалось ли malloc
выделить ненулевой блок памяти?
Как обнаружить сбой malloc?
Ответ 1
В соответствии с Single Unix Specification, malloc
вернет NULL
и установит errno
, когда он сработает.
Ответ 2
Я всегда делаю это:
tok = malloc( sizeof( char ) * ( strlen(tc) + 1 ) );
if( tok == NULL )
{
/* Malloc failed, deal with it */
}
Некоторые люди делают tok = (type) malloc( ... )
, но вы должны использовать результат, потому что, по-видимому, он покрывает некоторые неприятные ошибки. Я сделаю некоторые исследования и посмотрю, смогу ли я узнать, что они собой представляют.
Edit:
Кастинг malloc может скрыть отсутствующий #include <stdlib.h>
Я нашел эту ссылку, которая содержала очень хорошее объяснение:
http://cboard.cprogramming.com/faq-board/25799-faq-casting-malloc.html
"Итак, когда вы говорите это (char *) malloc (10)
Вы говорите, что принимаете все malloc возвращает, преобразует его в char *, и присваиваем это переменной в вопрос.
Это хорошо и хорошо, если malloc прототип правильно (путем включения stdlib.h), где он определяется как return void *.
Проблема возникает, когда вы не можете include stdlib.h, а компилятор изначально предполагает, что malloc возвращает int. Реальная проблема заключается в том, что вы НЕ ДОЛЖНЫ получить предупреждение от компилятора.
Вы весело конвертируете этот int в char * (через литой). На машинах где sizeof (char *) отличается от sizeof (int), код серьезно сломан.
Теперь, если у вас есть только char * var = malloc (10); И вы пропускаете включите, вы получите предупреждение от компилятора."
Ответ 3
Конечно. Портативный способ - проверить, возвращается ли malloc(...)
NULL
.
Ответ 4
Вы можете обнаружить сбой, если:
malloc(n)
возвращает NULL
Это самый распространенный и надежный тест для обнаружения отказа распределения. Если вы хотите быть переносимым за пределы POSIX/SUS, я бы не стал доверять errno
. Если вам нужны детали, скажем, для ведения журнала, я должен был бы обнулить errno
перед вызовом, посмотреть, изменилось ли оно, а затем, возможно, зарегистрировать это.
malloc(n)
возвращает не адрес NULL
, который не поддерживается фактической памятью
Прикоснитесь к нему и посмотрите, не убили ли вы ОС. Да, это может произойти. Он называл overcommit памяти и напоминает дробный резервный банк. Это оптимистичный подход к ОС или гипервизору для возврата адресов в виртуальную память, которую они играют в азартные игры, которые им никогда не понадобится. Это происходит на Linux, VMware. (Я не могу найти никаких явных доказательств чрезмерной обработки Windows, хотя запрошенные страницы только "зафиксированы" , когда они коснулись.)
Тогда возникает вопрос: "Как я уверенно обнаруживаю, что моя программа вот-вот потерпит крах при доступе к адресу, который я получил от malloc, которому я ранее доверял, как подростковая подача?". Одним из способов может быть read()
случайный файл в тестовой области и посмотреть, вернет ли ОС EINVAL или эквивалент.
Для дополнительных очков
malloc(0)
возвращает NULL
и оставляет errno
undefined
Я знаю, что вопрос задан для "ненулевого [размера] блока памяти", но это интересно. Рассмотрим SUS-совместимый распределитель, который намеревается вернуть не NULL
для распределения нулевого размера (он может это сделать), но затем он терпит неудачу, поэтому он должен вернуть NULL
. И он может попытаться установить errno
. Это провал? Я думаю, что Хоар говорит, что мы заплатили миллиард долларов за эту двусмысленность. Таким образом, вызов malloc(0)
не переносится, и, вероятно, этот вопросник знал об этом!
Ответ 5
malloc(n)
возвращает NULL
при ошибке. malloc(0)
может возвращать NULL
.
Чтобы обнаружить отказ:
void ptr = malloc(n);
if (ptr == NULL && n > 0) Handle_Failure();
Примечания:
Как и в случае OP: "... выделить ненулевой блок памяти", часто код таков, что запрос на размещение 0
не может быть выполнен, поэтому тест 0
не нужен.
size_t nstr = strlen(some_string) + 1;
void ptrstr = malloc(nstr);
if (ptrstr == NULL) Handle_Failure();
Некоторые системы устанавливают errno
при сбое, но не все. Установка errno
из-за сбоя выделения памяти не указана в спецификации C11.
malloc(n)
ожидает, что n
будет неподписанным типом size_t
. Использование int n
с отрицательным значением, безусловно, преобразуется в какое-то большое значение без знака, а затем, скорее всего, не удастся выделить память.