Можно ли использовать константную переменную для объявления размера массива в 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 (работает на микроcontrollerе и т. Д.), А не C, запущенном на моем рабочем столе. Таким образом, встроенная система должна иметь ROM (Flash, EEPROM …). Что будет тогда?

5 Solutions collect form web for “Можно ли использовать константную переменную для объявления размера массива в C?”

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

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

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

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

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

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

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

С enum :

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

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

С макросами:

 #define N 5 int is[N]; 

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

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

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

  • не находятся на C89, и только необязательно в C11
  • могут нанести накладные расходы: есть ли накладные расходы для использования массивов переменной длины? (вероятно, мало)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Может быть, стоит упомянуть, здесь вы можете использовать

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

Если вам понадобится количество элементов

  size_t sz = sizeof(b)/sizeof(b[0]); 

Я считаю, что дело до цепочки инструментов, чтобы решить, где хранить константы, флеш или оперативную память

  • Использует ли гибкие члены массива в C плохой практике?
  • Сохранение заказа с помощью LINQ
  • Почему scanf () нуждается в & operator (address-of) в некоторых случаях, а не в других?
  • Как создать точную копию массива?
  • Правильное распределение многомерных массивов
  • Swift: передать массив по ссылке?
  • Получите все неединственные значения (то есть: дублировать / более одного вхождения) в массиве
  • Подсчитайте вхождения, которые имеет определенное целое число в массиве
  • Как создать массив байтов из HttpPostedFile
  • Где Java-массив Array indexOf?
  • Добавить JsonArray в JsonObject
  • Interesting Posts

    Как запустить Eclipse с использованием новой версии 1.7 для JDK для Mac?

    Могу ли я повторно активировать клавиши курсора для изменения ссылки на ячейку в формуле?

    Что такое x после «x = x ++»?

    Как работает переполнение CSS: hidden, чтобы заставить элемент (содержащий плавающие элементы) обтекать плавающие элементы?

    Почему «source <(cmd)» работает, но не «$ (cmd)»

    Ошибка HTTP 500.19 – Внутренняя ошибка сервера

    В чем смысл метки «#» на быстром языке?

    VS2010 Как включить файлы в проект, скопировать их для автоматического создания выходного каталога во время сборки или публикации

    Редактор с использованием muti-line поиска и замены

    Не удается установить Google Chrome на Ubuntu 11.04

    Двойная загрузка различных версий Mac OS X

    IPN не был отправлен, а рукопожатие не было проверено. Проверьте информацию.

    Что означает «Только у ReactOwner могут быть ссылки». имею в виду?

    Как сохранить файл Excel как CSV, не теряя длинный текст?

    Какое допустимое магнитное поле (в Тесле) для жесткого диска?

    Давайте будем гением компьютера.