ISO C90 запрещает массив переменной длины

Я динамически вычисляю размер массива. Что-то типа:

void foo(size_t limit)
{
  char buffer[limit * 14 + 1];
}

Но только компилятор GCC говорит:

error: ISO C90 forbids variable length array ‘buffer’

поиск по SO я нашел этот ответ:

C99 §6.7.5.2:

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

Итак, я повторно объявил переменную типа ограничения размера, чтобы:

void foo(const size_t limit)

Но он продолжает предупреждать меня. Это ошибка GCC?


person Jack    schedule 19.04.2012    source источник
comment
Что ж, C90 != C99.   -  person user7116    schedule 19.04.2012
comment
Объявление size_t limit как const ничего не меняет. Это по-прежнему массив переменной длины, поскольку размер определяется во время выполнения.   -  person Mysticial    schedule 19.04.2012
comment
GCC сообщает вам, что с параметрами командной строки, которые вы используете, он по умолчанию компилируется в соответствии со стандартом C90. Цитируемый вами абзац взят из C99. Это причина вашей проблемы, а не тип limit.   -  person Pascal Cuoq    schedule 19.04.2012
comment
Следует отметить, что сам GCC поддерживает массивы переменной длины в качестве расширения языка, поэтому это будет работать, если вы не компилируете в режиме c99, но он не переносится, если вы всегда не будете использовать компилятор, который имеет такое расширение или реализует VLA C99. .   -  person wkl    schedule 19.04.2012
comment
Просто вызовите gcc с gcc -std=c99 -pedantic ...   -  person pmg    schedule 19.04.2012


Ответы (6)


const-квалификация переменной не делает ее константой времени компиляции (определение целочисленного константного выражения см. В C99 6.6 §6), и до введения массивов переменной длины с C99, размеры массивов должны быть константами времени компиляции.

Совершенно очевидно, что const-qualify переменная не делает ее константой времени компиляции, особенно в случае параметров функции, которые не будут инициализированы до тех пор, пока функция не будет вызвана.

Я вижу следующие варианты решения вашей проблемы:

  • скомпилируйте свой код как C99 через -std=c99 или -std=gnu99
  • выделите свой буфер через malloc()
  • используйте alloca(), если возможно, что ближе всего к массивам переменной длины с C90.
  • выберите максимальный размер буфера, который всегда используется, и завершите работу, если заданный limit аргумент переполнится

В качестве побочного примечания, даже несмотря на то, что C99 допускает массивы переменной длины, по-прежнему незаконно использовать значение целочисленной переменной со статической продолжительностью хранения в качестве размера для массива со статической продолжительностью хранения, независимо от const-квалификации: хотя нет ничего, что мешает это в принципе, если целочисленная переменная инициализируется в той же единице трансляции, вам придется использовать переменные особого случая с видимым определением от тех, чье определение находится в другой единице трансляции, и придется либо запретить предварительные определения, либо потребовать несколько проходов компиляции поскольку значение инициализации предварительно определенной переменной неизвестно до тех пор, пока не будет проанализирована вся единица перевода.

person Christoph    schedule 19.04.2012

const не представляет константу в C, а представляет собой переменную только для чтения.

#define SIZE 16
char bla[SIZE];   // not a variable length array, SIZE is a constant

но

const int size 16;
char bla[size];   // C99 variable length array, size is not constant
person ouah    schedule 19.04.2012

C90 не допускает массивов переменной длины. Однако для выполнения этой работы вы можете использовать компилятор c99-gcc.

Вы компилируете с c90-gcc, но смотрите спецификации C99.

person P.P    schedule 19.04.2012

Нет, это не ошибка. Вы не можете использовать VLA в C90. Когда вы заявили

const size_t limit

это не постоянное выражение. Постоянное выражение было бы чем-то вроде буквального значения 666.

Обратите внимание, что C в этом отношении значительно отличается от C ++. Даже такая константа

const int i = 666;

не является константным выражением в C.Это основная причина, по которой постоянные значения обычно объявляются с #define в C.

person David Heffernan    schedule 19.04.2012
comment
Большое спасибо за ваше объяснение. из любопытства, почему стандарт C90 не принимает такое постоянное выражение, которое я пытаюсь использовать? потому что, если я использую тип const, это означает, что я не могу изменить его позже, так в чем причина его запрета? и C99 std, иначе значение int не обязательно должно быть как минимум константного типа. Извините за мой плохой английский. :) - person Jack; 19.04.2012
comment
@Jack У тебя нет постоянного выражения. У вас есть const переменная. Постоянное выражение будет 42 или 66. - person David Heffernan; 19.04.2012

Как написано в вашем вопросе, это от C99, а не C90, вам необходимо скомпилировать его с C99, чтобы иметь возможность использовать массивы переменной длины.

person MByD    schedule 19.04.2012
comment
Или вы можете использовать alloca вместо этого. - person James McLaughlin; 19.04.2012
comment
Ага, но динамическое выделение памяти - это совсем другое. - person MByD; 19.04.2012
comment
Разве alloca не во многом то же самое, что использование массива переменной длины? (поскольку он использует стековую память, а не кучу) - person James McLaughlin; 19.04.2012

Квалифицированная переменная const не является целочисленным константным выражением в смысле стандарта. Это должна быть буквальная константа, константа перечисления, sizeof или какое-то выражение, составленное из них.

Если можете, переключитесь на C99. Параметр gcc - -std=c99 (или gnu99, если вам нужно расширение gnu.)

person Jens Gustedt    schedule 19.04.2012