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

Можно ли использовать константную переменную для объявления размера массива в C?

Почему следующий код выдает ошибку?

const int a = 5;
int b[a]={1,2,3,4,5};

А также, когда я попытался скомпилировать приведенный выше код без ключевого слова "const", я получил ту же ошибку:

int a = 5; 
int b[a]={1,2,3,4,5};

почему так? Какая ошибка я здесь делаю?

И еще один вопрос: Когда константы заменяются их фактическими значениями в коде, то есть, если я объявляю переменную say: const int x = 5; Я знаю, что память не выделяется в памяти для переменной x, но область постоянной переменной в ПЗУ содержит значение 5 и что x просто заменяется значением 5, где x появляется в коде. Но когда это происходит? Время компиляции? Время загрузки? Время предварительной обработки?

PS: Я говорю о Embedded C (работает на микроконтроллере и т.д.), а не C работает на моем рабочем столе. Таким образом, встроенная система должна иметь ROM (Flash, EEPROM...). Что будет тогда?

4b9b3361

Ответ 1

Это просто ограничение языка. Размеры статически ограниченных массивов должны быть постоянными выражениями, и, к сожалению, в C это только что-то вроде литеральной константы или выражения sizeof или такой, но не переменной const.

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

Вам может быть интересно узнать, что на С++ разные правила, где static const int действительно является константным выражением, а С++ 11 добавляет новое ключевое слово constexpr, чтобы еще более широко использовать постоянные выражения, которые охватывают больше вещей, значение которых "можно разумно определить во время компиляции".

Ответ 2

В C, const является неправильным для чтения только для чтения. переменные const могут изменять свое значение, например. вполне нормально объявлять

const volatile int timer_tick_register; /* A CPU register. */

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

Ответ 3

2 основных альтернативы VLA: enum и макросы

С enum:

enum N { N = 5 };
int is[N];

Это работает, потому что члены перечисления являются постоянными выражениями: Может ли член перечисления быть размером массива в ANSI-C?

С макросами:

#define N 5
int is[N];

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

Преимущество макросов заключается в том, что у вас больше контроля над типом констант (например, #define N 1 vs #define N 1u), а enum фиксированы для определенного типа реализации: Является ли sizeof (enum) == sizeof (int), всегда? Но в этом случае это не имеет большого значения.

Зачем избегать VLA

Ответ 4

EDIT: просто прочитайте в wikipedia, что C11 отнесла массивы переменной длины к необязательной функции:( Doh! Первая половина сообщения может быть не такой полезной, но вторая половина отвечает на некоторые из ваших другие вопросы:)

В дополнение к сообщению Kerrek SB, C99 (ISO/IEC 9899: 1999) имеет концепцию массива переменной переменной длины. Стандарт дает следующий пример:

#include <stddef.h>
size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}

Оператор sizeof расширяется следующим образом:

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражением или именем в скобках типа. Размер определяется по типу операнда. Результат - целое число. Если тип операнда - тип массива переменной длины, операнд оценивается; в противном случае операнд не оценивается, а результат - целочисленная константа.

Еще один приятный пример можно найти на wikipedia.

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

Что касается некоторых ваших других вопросов:

Q: Когда константы заменяются их фактическими значениями в коде?

Если константа является константной переменной, она никогда не может быть "заменена" и всегда доступна как область памяти. Это связано с тем, что адрес-оператор & все еще должен работать с переменной. Однако, если адрес переменной никогда не используется, он может быть "заменен" и не иметь выделенной памяти. Из стандарта C:

Реализация может поместить объект const, который не является изменчивым в только для чтения. Более того, внедрение не обязательно распределите хранилище для такого объекта, если его адрес никогда не используется.

Следующий вопрос...

В: Я знаю, что память не выделяется в ОЗУ для переменной x, но область постоянной переменной в ПЗУ содержит значение 5

Это зависит от вашей системы. Если у вас есть ПЗУ, и компилятор знает, где находится ПЗУ, то он вполне может быть помещен в ПЗУ. Если нет ПЗУ, то единственным выбором, который может быть у компилятора (ну, собственно, линкер), является ОЗУ.

Q: x просто заменяется значением 5, где x появляется в коде. Но когда это происходит? Время компиляции? Время загрузки? Время предварительной обработки?

Как уже отмечалось, это зависит от того, как используется константа. Если адрес константной переменной никогда не используется, а компилятор достаточно умен, то во время усложнения. В противном случае "замена" никогда не возникает, и это значение с местоположением в памяти; в этом случае размещение переменной в памяти происходит во время соединения. Это не произойдет во время предварительной обработки.