Когда допустимы массивы переменной длины? - PullRequest
4 голосов
/ 20 апреля 2011

Я не эксперт по C ++, но, насколько я знаю, этот код должен потерпеть неудачу из-за того, что size не является константой:

#include<iostream>

using namespace std;

int main(int argc, char** argv)
{
  int size = *argv[1] - 48;
  char array [size];
  cout<<sizeof(array)<<endl;

  return 0;
}

Почему это работает, когда я компилирую это с помощью gcc (лучше, скажем, g ++)?

./test 7
7
/test 2 
2

Ответы [ 7 ]

5 голосов
/ 20 апреля 2011

Чтобы выделить память из стека или кучи для переменной, размер переменной должен быть известен. Компиляторы C ++ могут сами решать, как они распределяют память, но c ++ обнародовал, как они ожидают, что компиляторы c ++ справятся с ситуацией, и, следовательно, c ++ std требует, чтобы производители компиляторов опубликовали свою обработку памяти. Это происходит через оператор sizeof. Этот оператор полностью вычисляется во время компиляции. Ограничение времени компиляции для размеров массива вытекает из этого требования.

int arr[10];
std::cout << sizeof(arr) << std::endl

, поскольку каждая переменная и тип поддерживает sizeof, их размеры необходимо вычислять во время компиляции в c ++. Таким образом, массивы переменной длины невозможны в c ++.

Существует еще одно очень важное ограничение, вытекающее из этого требования. В принципе, поставщики компилятора c ++ могли бы рассчитать максимальный объем памяти, необходимый для стека программы c ++, если бы не было одной проблемы: для рекурсивных функций вы не можете вычислить размер стека, используемый программой, но для всего остального размер стека может рассчитать, выполнив следующее:

  1. использовать sizeof (a) для каждой переменной в кадре стека
  2. сумма размеров переменных, чтобы получить объем памяти, необходимый для этого стекового кадра
  3. перечислить все возможные кадры стека и рассчитать их размеры
  4. Выберите стек вызовов, который имеет наибольший размер
  5. выберите этот размер в качестве размера стека вашей программы.

К сожалению, рекурсивные функции нарушают всю схему. И для анализа того, какие функции могут иметь бесконечные стеки вызовов, потребуется анализ глобального потока программы. Но ограничение для оператора sizeof во время компиляции является важным, иначе наши программы на c ++ могли бы случайно исчерпать пространство стека, вызывая сбои и нестабильность. И это недопустимо. Таким образом, каждая переменная и тип поддерживает оператор sizeof времени компиляции.

Поддержка VLA требует, чтобы компиляторы могли генерировать код, в котором смещения, обычно генерируемые как константы результирующего машинного кода, фактически модифицируются во время выполнения. Стандартные компиляторы c ++ обычно не имеют возможности сделать это. C решил добавить эту поддержку, и таким образом компиляторы C могут это сделать. Но в процессе им нужно было сломать оператор sizeof. Размеры больше не могут быть рассчитаны во время компиляции. Поддержка VLA, как указано в стандарте C, имеет большие проблемы:

  1. вы не можете поместить VLA в структуру или класс
  2. VLA в основном ограничены локальной областью действия

Эти проблемы уже решены в c ++ с помощью std :: vector, у которых нет ни одной из этих проблем.

3 голосов
/ 20 апреля 2011

Вот список новых функций в C99 , который добавляет массивы переменной длины .

Также см. $ 6.7.6.2 / 4 Деклараторы массива из N1548 ( ИСО / МЭК 9899: проект комитета 201x - 2 декабря 2010 г. N1548 ), в котором подробно это.

2 голосов
/ 20 апреля 2011

Это нестандартное расширение GCC - другие компиляторы, такие как Visual C ++, не поддерживают это.

1 голос
/ 24 июля 2013

c99 поддерживает массивы переменной длины (VLA), но ни c90, ни C ++ не поддерживают массивы переменной длины, но gcc поддерживает это как расширение как в C, так и в C ++ , которое вы можете видетьэто будет более понятно, если вы скомпилируете эти аргументы:

gcc -std=c89 -pedantic

. Это даст вам следующее предупреждение:

warning: ISO C90 forbids variable length array ‘array’ [-Wvla]

или g++:

g++ -pedantic

выдаст вам это предупреждение:

warning: ISO C++ forbids variable length array ‘array’ [-Wvla]

этот раздел standards в руководстве gcc содержит более подробную информацию.Важно отметить, что с 2011 года стандартные массивы переменной длины C (VLA) теперь являются необязательными.

1 голос
/ 20 апреля 2011

Это функция C99, которая позволяет объявлять такие массивы в стеке.

0 голосов
/ 20 апреля 2011

Потому что вы не вызываете g ++ как компилятор C ++.Если я пытаюсь это сделать, я получаю предупреждение, в котором четко говорится, что «ISO C ++ запрещает массив переменной длины».Но мои make-файлы включают параметр -std=c++98, по крайней мере, когда я хочу скомпилировать переносимый C ++.

0 голосов
/ 20 апреля 2011

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

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