Подтвердить что ты не робот

Размер массива С++, зависящий от параметра функции, вызывает ошибки компиляции

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

    void f(int n){
        char a[n];
    };

    int main() {
        return 0;
    }

Этот фрагмент кода отлично компилируется на GNU С++, но не на MSVC 2005.

Я получаю следующие ошибки компиляции:

    .\main.cpp(4) : error C2057: expected constant expression
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0
    .\main.cpp(4) : error C2133: 'a' : unknown size

Что я могу сделать, чтобы исправить это?

(Я заинтересован в том, чтобы сделать эту работу с MSVC, не используя new/delete)

4b9b3361

Ответ 1

Что вы нашли его одним из расширений компилятора Gnu на языке С++. В этом случае Visual С++ полностью корректен. Массивы в С++ должны быть определены с размером, являющимся выражением постоянной времени компиляции.

В обновлении 1999 года к этому языку была добавлена ​​функция, называемая массивами переменной длины, где это является законным. Если вы можете найти компилятор C, который поддерживает C99, что непросто. Но эта функция не является частью стандартного С++, но не будет добавлена ​​в следующее обновление к стандарту С++.

В С++ есть два решения. Первый заключается в использовании std::vector, второй - просто использовать оператор new []:

char *a = new char [n];

Пока я писал свой ответ, другой написал предложение использовать _alloca. Я бы настоятельно рекомендовал против этого. Вы бы просто обменялись одним нестандартным, не переносным методом для другого, точно так же, как и для компилятора.

Ответ 2

Ваш метод выделения из стека - расширение g++. Чтобы выполнить эквивалент в MSVC, вам необходимо использовать _alloca:

char *a = (char *)_alloca(n);

Ответ 3

Вы используете то, что не является стандартом. На самом деле это стандартный C, но не С++. Как это странно!

Объясняя немного больше, массивы стека времени выполнения не являются частью С++, но являются частью C99, последнего стандарта для C. Вот почему некоторые компиляторы получат его, а другие - нет. Я бы рекомендовал воздержаться от его использования, чтобы избежать проблем с совместимостью компилятора.

Альтернативная реализация функциональности будет использовать новые и удалить, как опубликовано strager.

Ответ 4

массив переменной длины был введен в C99. Он поддерживается в gcc, но не msvc. По словам человека в команде MSVC, Microsoft не планирует поддерживать эту функцию в своем компиляторе c/С++. Он предложил использовать std::vector в этих случаях.

Обратите внимание, что C99 не требует, чтобы массив был выделен в стеке. Компилятор может выделить его в кучу. Однако gcc выделяет массив в стеке.

Ответ 5

Вы можете использовать new/delete для выделения/свободной памяти в куче. Это медленнее и, возможно, больше подвержено ошибкам, чем использование char [n], но пока оно не является частью стандарта С++, к сожалению.

Вы можете использовать класс массива с расширенным охватом для безопасного для исключения метода использования нового []. delete [] автоматически вызывается в случае, когда он выходит из области видимости.

void f(int n) {
    boost::scoped_array<char> a(new char[n]);

    /* Code here. */
}

Вы также можете использовать std::vector и зарезервировать() несколько байтов:

void f(int n) {
    std::vector<char> a;
    a.resize(n);

    /* Code here. */
}

Если вы хотите использовать char [n], скомпилируйте как код C99 вместо кода на С++.

Если вам по какой-то причине необходимо выделить данные в стеке, используйте _alloca или _malloca/_freea, которые являются расширениями, предоставляемыми библиотеками MSVC и т.д.

Ответ 6

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


char *a = new char [n];

'a' is still a local variable allocated on the stack, but instead of being the whole array (which has variable length), it just a pointer to an array (which is always the same size, and thus known at compile time). The array is allocated on the heap, which typically plays the stack counterpart -- the stack is for things with a size known at compile time, and the heap is for things with a size not known at a compile time.

Ответ 7

Можно ли использовать vector<> вместо массива? Или, поскольку вы заменяете char *, a std::string? Это хорошо работает с определением времени выполнения, хотя могут быть и другие причины не использовать их.