Как компилятор разрешает адрес переменной, объявленной после массива переменной длины?

Предположим, у меня есть следующая функция, использующая массив переменной длины:

void func(int size)
{
    int var1;
    int arr[size];
    int var2;
    ...
}

Как компилятор определяет адрес var2?

Единственный способ, который я могу придумать, это поместить arr после var1 и var2.

Но в таком случае, что, если массивов переменной длины несколько?

Размещение их всех после «обычных» переменных помогло бы разрешить только адрес первой.

Мое неявное предположение состоит в том, что все локальные переменные (включая VLA) размещены в стеке.

Я понимаю, что это не определено стандартом C99, поэтому вопрос по сути о компиляции.


person barak manos    schedule 28.07.2014    source источник
comment
Это действительно имеет значение? И он нигде не указан, компилятор может разместить его где угодно, и он может отличаться от компилятора к компилятору. Кроме того, в спецификациях фактически ничего не говорится о стеках, и существуют системы без стека, на которые нацелены компиляторы C.   -  person Some programmer dude    schedule 28.07.2014
comment
@DavidHeffernan: Ну ... Разве нет стандарта, которому компиляторы должны следовать и реализовывать VLA?   -  person barak manos    schedule 28.07.2014
comment
@JoachimPileborg: тот же комментарий, что и выше.   -  person barak manos    schedule 28.07.2014
comment
@barak любой компилятор может делать это так, как ему нравится. Стандарт определяет что делает компилятор, а не как он это делает.   -  person David Heffernan    schedule 28.07.2014
comment
var2 не обязательно располагать на фиксированном смещении от чего-либо. Компилятор может написать дополнительный код для вычисления местоположений вместо использования фиксированных смещений. Он уже делает это, чтобы вычислить, где находится arr, предполагая, что VLA находятся в стеке, а стек растет вниз.   -  person user2357112 supports Monica    schedule 28.07.2014
comment
@user2357112: Вау, это может привести к серьезным последствиям для производительности...   -  person barak manos    schedule 28.07.2014
comment
Компилятор @barak может делать это как угодно, пока он работает   -  person David Heffernan    schedule 28.07.2014
comment
@DavidHeffernan: Значит, вы (лично) не стали бы использовать VLA в приложении RT...?   -  person barak manos    schedule 28.07.2014
comment
Я просто пытаюсь заставить вас понять, что реализация зависит от компилятора.   -  person David Heffernan    schedule 28.07.2014


Ответы (2)


Вот одна из возможных моделей. Думайте о arr как об указателе (фиксированного размера) на массив, размещенный в стеке:

int var1;
int *arr = alloca(sizeof(int) * size);
int var2;

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

Обратите внимание, что это только пример. Каждый компилятор может свободно реализовывать VLA, как ему заблагорассудится. Если вы хотите узнать, что делает ваш компилятор, посмотрите на сгенерированный ассемблерный код.

person NPE    schedule 28.07.2014
comment
Значит, мое предположение о том, что VLA всегда размещаются в стеке, неверно? - person barak manos; 28.07.2014
comment
@barakmanos: это не указано. В модели, предложенной в ответе, arr_data попадает в стек. - person NPE; 28.07.2014
comment
О, значит, вы размещаете все VLA после обычных переменных? - person barak manos; 28.07.2014
comment
@barakmanos: Да, это идея (не единственная возможная идея, заметьте). - person NPE; 28.07.2014
comment
Спасибо!!! Не могли бы вы объяснить alloca? Это в куче? В конце стека? - person barak manos; 28.07.2014
comment
@barakmanos: alloca находится в стеке, и это специальная функция, о которой компилятор знает внутренне (то есть ее нельзя написать на стандартном C). - person user541686; 28.07.2014
comment
@barakmanos Да, но даже без учета этого примера. С точки зрения стандарта C не существует таких вещей, как стек или куча — это просто деталь реализации. - person The Paramagnetic Croissant; 28.07.2014
comment
@TheParamagneticCroissant: Как я уже сказал в конце ответа: я понимаю, что это не определено стандартом C99, поэтому вопрос, по сути, касается компиляции. - person barak manos; 28.07.2014
comment
@barakmanos Еще одна ваша цитата: нет ли стандарта, которому компиляторы должны следовать и реализовывать VLA? - person David Heffernan; 28.07.2014
comment
@DavidHeffernan: Да, в одном из комментариев выше. Что-то явно не так с этим вопросом? - person barak manos; 28.07.2014
comment
Я просто возражаю против вашего комментария к @ThePara MagneticCroissant, что было разумно для меня, учитывая вопрос и ваши комментарии. - person David Heffernan; 28.07.2014

Шаг 1: Для каждого элемента размера переменной создайте скрытую переменную, содержащую указатель на массив, и скрытую переменную, содержащую размер массива. Их можно оптимизировать, присвоить регистрам и т. д. как любую другую переменную.

Шаг 2: Выделите место для элементов неизменного размера обычным способом.

Шаг 3: Чтобы обработать объявление элемента переменного размера, оцените размер и сохраните его в переменной размера. Рассчитайте место для элемента переменного размера с учетом выравнивания. Освободите место в стеке для элемента переменного размера, затем сохраните указатель на расположение элемента в переменной скрытого указателя.

Шаг 4: Используйте скрытую переменную-указатель для доступа к элементам массива. Используйте скрытую переменную размера для оператора sizeof.

person gnasher729    schedule 28.07.2014