Требуется ли выделение массива переменной длины C из стека?

После удаления всех вызовов malloc и calloc из нашего кода для встраиваемой системы я с удивлением обнаружил, что malloc все еще связывается. График вызовов указал мне на функцию, которая не имела явных вызовов * alloc и не вызывала любые библиотечные функции, которые могут быть выделены, например strdup.
Мне пришлось взглянуть на сгенерированную сборку, чтобы понять, что это произошло из-за встроенной функции, содержащей VLA.

Я думал, что VLA нужно размещать в стеке. Этот компилятор сломан?


person AShelly    schedule 08.10.2015    source источник
comment
Насколько большие выделенные VLA по сравнению с размером стека программы?   -  person Matt    schedule 08.10.2015
comment
В этом случае параметр размера был uint8_t, поэтому в худшем случае было 256 байтов, примерно 1/5 стека.   -  person AShelly    schedule 08.10.2015
comment
Если нет шанса на переполнение стека (я имею в виду настоящий :-), почему бы не использовать просто худший случай, то есть какой-нибудь char arr[256] вместо VLA?   -  person Matt    schedule 08.10.2015
comment
Я изменил его на исправленный. Суть вопроса - развенчать распространенное предположение , что VLA являются всегда штабелировать.   -  person AShelly    schedule 08.10.2015


Ответы (2)


Не требуется, чтобы VLA выделялись из стека (в стандарте языка даже не упоминаются стеки или кучи). Единственное требование:

6.2.4 Storage durations of objects
...
7 For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration.35) If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.
35) Leaving the innermost block containing the declaration, or jumping to a point in that block or an embedded block prior to the declaration, leaves the scope of the declaration.

Учитывая это, имеет смысл выделять из стека, но для очень больших объектов это может быть невозможно, и вместо этого такой объект может быть выделен из кучи или какого-либо другого сегмента памяти. Бухгалтерия зависит от реализации.

person John Bode    schedule 08.10.2015
comment
Большинство реальных реализаций просто дают сбой, если вы превышаете их пределы размера стека, создавая слишком большой VLA или их последовательность в цепочке вызовов функций. Используйте VLA только в том случае, если вы знаете, что размер будет ограничен, и даже в этом случае будьте осторожны с функциями, не являющимися листовыми. Реализация могла бы разрешить спасти вас от вас самих, выделив VLA отдельно, но это не обязательно. - person Peter Cordes; 01.07.2020

Нет, их не нужно размещать в стеке. Я бы использовал alloca, если вы хотите, чтобы он был в стеке.

Источник 1: https://stackoverflow.com/a/2035292/283342

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

Источник 2: https://en.wikipedia.org/wiki/Variable-length_array.

Одной из проблем, которые могут быть скрыты поддержкой языка VLA, является проблема распределения базовой памяти: в средах, где существует четкое различие между кучей и стеком, может быть неясно, в каком из них (если таковые имеются) будут храниться VLA.

person Adrian    schedule 08.10.2015