Книга: Linux программирование в примерах
3.2.4. Вызовы ленивых программистов: alloca()
3.2.4. Вызовы ленивых программистов: alloca()
«Опасность, Билл Робинсон! Опасность!»
Есть еще одна дополнительная функция выделения памяти, о которой вам нужно знать. Мы обсуждаем ее лишь для того, чтобы вы поняли ее, когда увидите, но не следует использовать ее в новых программах! Эта функция называется alloca()
; она объявлена следующим образом:
/* Заголовок в GNU/Linux, возможно, не на всех Unix-системах */
#include <alloca.h> /* Обычный */
void *alloca(size_t size);
Функция alloca()
выделяет size
байтов из стека. Хорошо, что выделенная память исчезает после возвращения из функции. Нет необходимости явным образом освобождать память, поскольку это осуществляется автоматически, как в случае с локальными переменными.
На первый взгляд, alloca()
выглядит чем-то типа панацеи для программистов, можно выделять память, о которой можно вовсе не беспокоиться. Подобно Темной Стороне Силы, это, конечно, привлекает. И подобным же образом этого нужно избегать по следующим причинам:
• Функция не является стандартной; она не включена ни в какой стандарт, ни в ISO, ни в С или POSIX.
• Функция не переносима. Хотя она существует на многих системах Unix и GNU/Linux, она не существует на не-Unix системах. Это проблема, поскольку код часто должен быть многоплатформенным, выходя за пределы просто Linux и Unix.
• На некоторых системах alloca()
невозможно даже реализовать. Весь мир не является ни процессором Intel x86, ни GCC.
• Цитируя справку[45] (добавлено выделение): «Функция alloca
зависит от машины и от компилятора. На многих системах ее реализация ошибочна. Ее использование не рекомендуется».
• Снова цитируя справку: «На многих системах alloca
не может быть использована внутри списка аргументов вызова функции, поскольку резервируемая в стеке при помощи alloca
память оказалась бы в середине стека в пространстве для аргументов функции».
• Она потворствует неряшливому программированию. Тщательная и корректная работа с памятью не сложна; вам просто нужно подумать о том, что вы делаете, и планировать заранее.
GCC обычно использует встроенную версию функции, которая действует с использованием внутритекстового (inline) кода. В результате есть другие последствия alloca()
. Снова цитируя справку:
Факт, что код является внутритекстовым (inline), означает, что невозможно получить адрес этой функции или изменить ее поведение путем компоновки с другой библиотекой.
Внутритекстовый код часто состоит из одной инструкции, подгоняющей указатель стека, и не проверяет переполнение стека. Поэтому нет возврата NULL
при ошибке.
Справочная страница не углубляется в описание проблемы со встроенной alloca()
GCC. Если есть переполнение стека, возвращаемое значение является мусором. И у вас нет способа сообщить об этом! Это упущение делает невозможным использование GCC alloca()
в устойчивом коде.
Все это должно убедить вас избегать alloca()
в любом новом коде, который вы пишете. В любом случае, если приходится писать переносимый код с использованием malloc()
и free()
, нет причины в использовании также и alloca()
.
- 3.2.3. Системные вызовы: brk() и sbrk()
- Глава 5 Системные вызовы
- Глава 7 Системные вызовы в UNIX
- 9.2. Системные вызовы
- Системные вызовы и драйверы устройств
- Системные вызовы управления процессорной привязкой
- Вызовы функций
- Другие системные вызовы для управления файлами
- Прототипы – это опора программистов
- 21.4 Вызовы socket
- 4.3. PROCESSOR ALLOCATION
- 4.3.1. Allocation Models