Каков переносимый способ проверить, не удалось ли 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 с отрицательным значением, безусловно, преобразуется в какое-то большое значение без знака, а затем, скорее всего, не удастся выделить память.