Странное назначение типа для индекса массива в C++

Привет у меня есть пример программы

#include <iostream>

int main() {
    int a = -5;
    int arr[a];
    std::cout << "Size of arr: " << sizeof(arr) << std::endl;
    return 0;
}

Здесь я получаю вывод 17179869164.

Мой вопрос в том, что значение размера массива не должно принимать отрицательные значения! и если я попытаюсь дать [-5], это выдаст ошибку. но теперь, как я получаю вывод 17179869164.

У меня тоже есть предположение: -5 преобразуется в беззнаковое целочисленное значение 4294967291, а общий размер задается как 17179869164 = 4294967291 * 4 (размер int).

Итак, я хотел знать, почему компилятор преобразует тип signed int в unsigned int и не выдает ошибку времени компиляции. Мне нужно было четкое понимание того, как компилятор выполняет этот фрагмент кода?


person Karthikgr    schedule 10.01.2020    source источник
comment
Ваша программа является недействительной C++ (независимо от значения a), потому что C++ не имеет variable- массивы длины.   -  person Some programmer dude    schedule 10.01.2020
comment
@Someprogrammerdude спасибо за информацию, я этого не знал. Но если я выполняю его, у него есть полная программа на C с изменениями, я получаю размер как -20% в gcc, но не должен ли он указывать это как ошибку компилятора для предоставления отрицательного значения?   -  person Karthikgr    schedule 10.01.2020
comment
Какой компилятор вы используете? Visual Studio 2019 выдает ошибки компиляции как для массива переменной длины (как указано @Someprogrammerdude), так и, как только вы это исправите, для a отрицательного значения.   -  person Frodyne    schedule 10.01.2020
comment
@Frodyne Я использую код Visual Studio с компилятором g++ и gcc.   -  person Karthikgr    schedule 10.01.2020


Ответы (3)


Для C++ массивы переменной длины не предусмотрены стандартом, но могут быть предоставлены расширением компилятора. Для C короткий ответ заключается в том, что стандарт преобразует значение в положительное целочисленное значение, если только оно не является постоянным выражением - в вашем случае это приводит к использованию беззнакового значения (использование двух дополнительных значений в качестве положительного значения). Конкретно:

Стандарт C11 — 6.7.6.2 Деклараторы массивов (стр. 5)

Если размер является выражением, которое не является целочисленным константным выражением: если оно встречается в объявлении в области действия прототипа функции, оно обрабатывается так, как если бы оно было заменено на *; в противном случае каждый раз, когда он оценивается, он должен иметь значение больше нуля.

person David C. Rankin    schedule 10.01.2020

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

Кто-то еще спросил что-то подобное здесь: Объявление массива отрицательной длины

person Michizev    schedule 10.01.2020

Я заметил интересное поведение в GodBolt.

Я взял ваш код и добавил вторую копию, где a объявлен константой:

#include <iostream>

int foo() {
    int a = -5;
    int arr[a];
    std::cout << "Size of arr: " << sizeof(arr) << std::endl;
    return 0;
}

int bar() {
    const int a = -5;
    int arr[a];
    std::cout << "Size of arr: " << sizeof(arr) << std::endl;
    return 0;
}

Затем я бросил им GCC, Clang и MSVC.

Насколько я знаю, GCC и Clang оба поддерживают массивы переменной длины (VLA) в качестве «дополнительной функции», и оба они съели foo без единой жалобы. Принимая во внимание, что MSVC, который не поддерживает VLA, жаловался.

С другой стороны, ни один из них не принял bar из-за того, что a был отрицательным.

Что касается того, почему GCC и Clang не могут сказать, что aотрицательно в foo, я оставлю это как вопрос для людей, более разбирающихся в компиляторах, чем я.

person Frodyne    schedule 10.01.2020