Я понимаю, какие массивы переменной длины и как они реализованы. Этот вопрос касается того, почему они существуют.
Мы знаем, что VLA разрешены только внутри функциональных блоков (или прототипов) и что они в принципе не могут быть нигде, кроме стека (при условии нормальной реализации): C11, 6.7.6.2-2:
Если идентификатор объявлен как имеющий измененный тип, он должен быть обычным идентификатор (как определено в 6.2.3), не имеют привязки и имеют либо масштаб или функцию блока прототип. Если идентификатор объявлен как объект со статическим или потоковым хранилищем длительность, он не должен иметь тип массива переменной длины.
Возьмем небольшой пример:
void f(int n)
{
int array[n];
/* etc */
}
есть два случая, о которых нужно позаботиться:
-
n <= 0
:f
должен защититься от этого, в противном случае поведение undefined: C11, 6.7.6.2-5 (основное внимание):Если размер является выражением, которое не является целочисленным постоянным выражением: если оно встречается в объявлении в области прототипа функции, обрабатывается так, как если бы он был заменен на
*
; в противном случае, каждый раз, когда он оценивается, он должен иметь значение больше нуля. Размер каждого экземпляра типа массива переменной длины не изменяется в течение его срока службы. Где размер выражение является частью операнда оператораsizeof
и изменяет значение выражение размера не повлияет на результат оператора, не определено, независимо от того, выражение размера оценивается. -
n > stack_space_left / element_size
: Нет стандартного способа определения того, сколько осталось пространства стека (поскольку нет такой вещи, как стек, если речь идет о стандарте). Таким образом, этот тест невозможно. Единственное разумное решение состоит в том, чтобы иметь предопределенный максимально возможный размер дляn
, скажемn
, чтобы убедиться, что переполнение стека не происходит.
Иными словами, программист должен убедиться, что 0 < n <= N
для некоторого n
выбора. Тем не менее, программа должна работать для n == N
в любом случае, поэтому можно также объявить массив с постоянным размером n
, а не переменной длиной n
.
Мне известно, что VLAs были введены для замены alloca
(как упоминалось в этом ответе), но в действительности они - одно и то же (присвойте переменный размер память в стеке).
Итак, вопрос в том, почему существует alloca
и, следовательно, существует VLA и почему они не устарели? Единственный безопасный способ использования VLA кажется мне ограниченным, и в этом случае принятие нормального массива с максимальным размером всегда является жизнеспособным решением.