Как gcc выделяет статически во время выполнения известную длину массива

Я написал следующий код:

int tester(int n)
{
int arr[n];
// ...
}

Этот код скомпилирован, без предупреждений, с использованием g ++.

Мой вопрос — как? Параметр n известен только во время выполнения, в массиве он статически размещается. Как gcc компилирует это?

3

Решение

Это расширение, которое GCC предлагает для C ++, хотя массивы переменной длины («VLA») должным образом поддерживаются C начиная с C99.

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

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

7

Другие решения

Библиотека GNU C предоставляет функцию для выделения памяти в стеке — ALLOCA (3). Он просто уменьшает указатель стека, создавая на нем некоторое пространство для царапин. GCC использует alloca(3) реализовать массивы переменной длины C99 — сначала он уменьшает указатель стека в прологе функции, чтобы создать пространство для всех автоматических переменных, размер которых известен во время компиляции, а затем использует alloca(3) в дальнейшем уменьшить его и освободить место для arr с размером, определенным во время выполнения. Оптимизатор может фактически объединить оба уменьшения.

int tester(int n)
{
int arr[n];
return 0;
}

компилируется в

;; Function tester (tester)

tester (int n)
{
int arr[0:D.1602D.1602] [value-expr: *arr.1];
int[0:D.1602D.1602] * arr.1;
long unsigned int D.1610D.1610;
int n.0;
...

<bb 2>:
n.0 = n;
...
D.1609D.1609 = (long unsigned int) n.0;
D.1610D.1610 = D.1609D.1609 * 4;
D.1612D.1612 = __builtin_alloca (D.1610D.1610); <----- arr is allocated here
arr.1 = (int[0:D.1602D.1602] *) D.1612D.1612;
...

Это эквивалентно следующему коду C:

int tester(int n)
{
int *arr = __builtin_alloca(n * sizeof(int));
return 0;
}

__builtin_alloca() внутренняя реализация GCC alloca(3),

3

По вопросам рекламы [email protected]