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

StackOverflow https://stackoverflow.com/questions/312116

Вопрос

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

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

    int main() {
        return 0;
    }

Этот фрагмент кода отлично компилируется на ГНУ С++, но не на 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 без использования нового/удаления)

Это было полезно?

Решение

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

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

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

char *a = new char [n];

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

Другие советы

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

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

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

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

Альтернативной реализацией функциональности было бы использование new и delete в соответствии с публикацией strager.

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

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

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 вместо кода C ++.

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

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

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

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


char *a = new char [n];

'a' по-прежнему является локальной переменной, размещенной в стеке, но вместо всего массива (имеющего переменную длину) это просто указатель на массив (который всегда имеет одинаковый размер и, следовательно, известен во время компиляции).Массив размещается в куче, которая обычно является аналогом стека: стек предназначен для объектов, размер которых известен во время компиляции, а куча — для объектов, размер которых неизвестен во время компиляции.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top