Почему размер глобального массива должен быть целочисленной константой?

В С++ я попытался объявить глобальный массив некоторого размера. Я получил ошибку:

привязка массива не является целочисленной константой перед токеном «]»

Но когда я объявил массив того же типа в функции main(), он работает нормально.

Почему здесь другое поведение?

int y=5;
int arr[y];         //When I comment this line it works fine

int main()
{
    int x=5;
    int arr2[x];        // This line doesn't show any error.
}

Изменить: многие предполагают, что этот вопрос является дубликатом Привязка массива ошибок не является целочисленной константой перед токеном ']'. Но этот вопрос не отвечает, почему существует другое поведение.


person Syed Maqthyar    schedule 10.03.2020    source источник
comment
Даже в main это нелегально, там используется расширение VLA.   -  person Jarod42    schedule 10.03.2020
comment
Границы всех массивов в C++ должны иметь значение, известное во время компиляции. Если такой код при размещении в main принимается вашим компилятором: вы используете расширение компилятора, которое позволяет компилировать VLA, даже если они не поддерживаются стандартом C++.   -  person Algirdas Preidžius    schedule 10.03.2020
comment
не путайте отсутствие ошибок компилятора с работает нормально. В этом случае работа в порядке означает, что ваш код полагается на нестандартное расширение, предоставленное компилятором, т.е. это нормально, но это не переносимый С++.   -  person 463035818_is_not_a_number    schedule 10.03.2020
comment
Почему бы не объявить y и x как const? Вам нужно изменить значение y или x? Надеюсь, что нет, потому что возникает много вопросов о том, насколько большими должны быть arr и arr2, особенно в отношении порядка инициализации. (Подсказка: они должны быть константами)   -  person Wyck    schedule 10.03.2020
comment
Скомпилируйте свою программу с помощью --std=c++17 (или --std=c++11, если это более старый компилятор), и компиляция завершится ошибкой.   -  person einpoklum    schedule 10.03.2020
comment
// This line doesn't show any error -- Да, это так. (rextester.com/NXZDT64108)   -  person PaulMcKenzie    schedule 10.03.2020


Ответы (4)


Оба примера некорректны в C++. Если компилятор не диагностирует последний, то он не соответствует стандарту.

Почему здесь другое поведение?

Вы используете расширение языка, которое позволяет использовать автоматические массивы длины во время выполнения. Но не разрешает статические массивы длины времени выполнения. Глобальные массивы имеют статическое хранилище.

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

person eerorika    schedule 10.03.2020

Размер массива должен быть постоянным. Вы можете исправить это, объявив y как const.

const int y=5;
int arr[y]; 

Что касается того, почему это работало в main, g++ позволяет использовать массив переменной длины в области блока в качестве расширения. Однако это не стандартный С++.

person dbush    schedule 10.03.2020

Оба не должны использоваться, один работает, потому что (как сказал @eerorika) массивы автоматической длины разрешены во время выполнения, но глобальные массивы должны иметь статическое хранилище.

Если вы хотите объявить массив с переменным размером (например, заданным std::cin), вы должны сделать что-то вроде:

int x;
std::cin >> x;
const int n = x;
float arr[n];

Но вы не сможете настроить его так, чтобы он содержал только нули с помощью float arr[n] = {0} (если вам нужно добавить значение в массив, не будучи уверенным, что вы его установили), вам нужно будет использовать такой цикл

for(int i = 0; i < n; i++)
{
    arr[i] = 0;
}
person Misty    schedule 10.03.2020
comment
Ваш пример все еще плохо сформирован, несмотря на использование const. Размер должен быть постоянным выражением времени компиляции. То, что вы получаете из ввода во время выполнения, конечно, не удовлетворяет этому. - person eerorika; 10.03.2020
comment
Утверждение, что «оба не должны использоваться», неуместно. Можно было бы пожелать избежать использования массива переменной длины для написания переносимого кода C++. Кто-то может захотеть использовать массив переменной длины для достижения желаемой цели проекта за счет переносимости. Ценности этих целей субъективны и косвенны, и вы не можете сказать, где баланс для другого человека. - person Eric Postpischil; 10.03.2020
comment
@EricPostpischil Вы правы, но когда вы используете изменяемую переменную, вы можете изменить ее, и из соображений безопасности лучше оставить ее константной. - person Misty; 11.03.2020

Система типов C++ обрабатывает эти C-подобные массивы так, как она определяет arr2 из вашего примера типа int[5]. Итак, да, количество элементов массива является частью типа!

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

Итак, вы можете изменить свой код на что-то вроде следующего, который будет иметь еще одно преимущество. Он правильно инициализирует массив:

int arr2[] = {0, 0, 0, 0, 0};   
person salchint    schedule 09.04.2020