Как компиляторы обрабатывают массивы переменной длины - PullRequest
10 голосов
/ 02 октября 2011

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

#include<iostream>

int main(){
  int n;
  std::cin>>n;
  int a[n];
}

Из того, что я узналв C все значения инициализатора должны быть постоянными, чтобы компилятор знал, сколько памяти следует зарезервировать внутри функции, обычно вычитая указатель стека для размещения количества элементов, которые содержит массив.

Это имеет смысл для меня.Тем не менее, я не совсем понимаю, как компиляторы обрабатывают вышеуказанную программу, так как она, кажется, работает с G ++ (MinGW), но не работает с Cl, компилятором C ++ от Microsoft.Я подозреваю, что GCC выделяет память в куче через нестандартное расширение, но я не уверен в этом.

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

Ответы [ 4 ]

12 голосов
/ 02 октября 2011

В версии C99 стандарта C допускаются массивы переменной длины.Однако они не разрешены ни в одной версии C ++;вы видите расширение G ++.Обратите внимание, что компилятор C от Microsoft не полностью поддерживает C99;поскольку G ++ поддерживает C99, достаточно легко применить поддержку VLA к C ++ в качестве расширения.

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

5 голосов
/ 02 октября 2011

Нет абсолютно никаких проблем с "вычитанием указателя стека" во время выполнения, значением времени выполнения.И именно так компиляторы обычно реализуют массивы переменной длины.Они «вычитают указатель стека» во время выполнения, когда фактический размер массива уже известен.Это все, что нужно сделать.(Нет необходимости выделять память для кучи, и я не знаю, что заставило вас подозревать это в GCC.).

Такая функциональность была доступна задолго до того, как VLA стали частью языка.[Нестандартная] функция alloca делает именно это.Единственное отличие состоит в том, что память, выделенная alloca, автоматически освобождается при выходе из функции, в то время как локальные VLA должны подчиняться стандартным правилам времени жизни на основе блоков.Последнее вообще не является проблемой, поскольку блочное гнездо выполняется в виде стека.

Другими словами, для значения времени выполнения n объявление

int a[n];

по сути, переводится во что-то вроде

int *a = alloca(n * sizeof *a);

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

2 голосов
/ 02 октября 2011
int main(){
  int n;
  std::cin>>n;
  int a[n];
}

Это не разрешено C ++.G ++ принимает массивы переменной длины как расширение, но VLA не являются частью стандарта C ++.Они являются частью стандарта C99, который поддерживает GCC (я не уверен в какой степени), но MSVC - нет.

2 голосов
/ 02 октября 2011

Никакая версия C ++ не допускает массив переменной длины. Только C99 позволяет это.

GCC позволяет использовать его как расширение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...