const value или #define, какой ресурс чипа будет использоваться?

если я определяю макрос или использую статическое константное значение во встроенной системе,
какой тип памяти будет использоваться, флэш-память или оперативная память? Какой способ лучше?


person user1287356    schedule 23.03.2012    source источник
comment
Как и любое другое значение, оно будет находиться в оперативной памяти во время выполнения программы и, возможно, в самом исполняемом файле.   -  person Niklas B.    schedule 23.03.2012
comment
Вы имели в виду '#определить макрос'?   -  person gbulmer    schedule 23.03.2012
comment
Имейте в виду, что это решение не ограничивается тем, какой ресурс будет использоваться... проверка типов, соблюдение правил области действия. Подробнее см. этот вопрос.   -  person semaj    schedule 23.03.2012


Ответы (3)


Что ж, если вы #define макрос, для него не выделяется дополнительная память или место для кода (flash). Вся работа выполняется на этапе компиляции.

Если вы используете глобальную переменную static const, двоичные коды будут сгенерированы для начального значения и памяти, выделенной для него. используется как флэш-память (размер bin-файла больше), так и память (чип-RAM).

person Albert    schedule 23.03.2012

Я считаю, что ответ более сложный.

Изменить: я прошу прощения за использование «должен» и «может», но без специального компилятора или отладчика я считаю, что это должно быть точным и точным. Может быть, если в вопросе можно будет сказать, какой компилятор и платформа предназначены, мы сможем быть яснее?

  1. #define NAME ((type_cast)value) не занимает места, пока не появится в коде. Компилятор может быть в состоянии вывести что-то, используя его значение (по сравнению с использованием переменной с неизвестным значением времени выполнения), и, следовательно, может изменить сгенерированный код, чтобы он фактически не занимал места, или может даже уменьшить размер кода. Если анализ компилятора заключается в том, что литеральное значение потребуется во время выполнения, то оно займет место в коде. Буквальное значение известно, поэтому компилятор должен иметь возможность выделить оптимальное количество места. В зависимости от процессора он должен храниться во флэш-памяти, но может быть не встроенным кодом, а вместо этого в «буквальном пуле», наборе локальных переменных, обычно рядом с кодом, поэтому можно использовать компактные адреса. Компилятор, скорее всего, примет правильное решение.

  2. static const type name = value; не должен занимать место до тех пор, пока он не будет использован в коде. Даже когда он используется в коде, он может потреблять или не потреблять «пространство» в зависимости от вашего компилятора (и, я думаю, стандарта C, который он компилирует) и того, как код использует это значение.

    Если адрес имени никогда не используется, то компилятору не нужно его сохранять. Если адрес значения взят (и этот код не удален), то значение должно быть в памяти. Умные компиляторы определят, берет ли какой-либо код в исходном файле его адрес. Даже если оно может быть сохранено, компилятор может сгенерировать лучший (более быстрый или более компактный код), не используя сохраненное значение.

    Компилятор может работать так же хорошо, как #define NAME, хотя может быть и хуже, чем #define.

    Если для значения был взят адрес, то компилятор обрабатывает переменную как инициализированную переменную, которая занимает место для хранения постоянного значения. Компилятор на самом деле не помещает значения в ОЗУ или флэш-память. Это зависит от линкера. В gcc есть «атрибуты», которые можно использовать, чтобы указать компоновщику, в какой сегмент поместить переменную. По умолчанию компилятор помещает инициализированные переменные в сегмент данных по умолчанию и инициализирует const в сегмент только для чтения. Используя атрибуты, программист может поместить переменные в любой сегмент. С помощью соответствующего скрипта компоновщика, который обычно входит в набор инструментов, сегменты можно поместить во флэш-память. Gcc использует сегмент данных только для чтения для таких данных, как литеральные строки.

    name должен быть доступен в отладчике, а #define NAME — нет.

  3. Существует третий подход, который заключается в использовании перечисления:

    перечисление КОНСТАНТЫ { имя = 1234, высота = 456 ... };

    Компилятор может обрабатывать их как #define constants, хотя они не такие гибкие, поскольку имеют размер int (IIRC). Невозможно получить адрес значения перечисления, поэтому у компилятора есть столько возможностей для создания хорошего кода, сколько #define NAME. Они часто будут доступны в отладчике.

  4. const type name = value; может потреблять оперативную память. Он должен быть в памяти, потому что компилятор не может знать, использует ли его код в другом файле или берет его адрес (но gcc LTO может это изменить). код пытается изменить значение, например, с помощью оператора присваивания. Обычно переменные, хранящиеся в ОЗУ, хранятся в сегментах памяти данных или bss. По умолчанию gcc помещает const в сегмент только для чтения, сегмент можно установить с помощью параметра командной строки -mrodata=раздел только для чтения. этот сегмент — .rodata на ARM.

Во встроенных системах все инициализированные глобальные и статические переменные (const или нет) также хранятся во флэш-памяти и копируются в ОЗУ при запуске программы (до вызова main()). Все неинициализированные глобальные или статические переменные устанавливаются в 0 перед вызовом main().

Компилятор может поместить const переменных в свой собственный сегмент памяти (gcc делает), что может позволить сценарию компоновщика (например, ld) поместить их во флэш-память и не выделять им ОЗУ (это не будет работать, например, на AVR ATmega, который используйте разные инструкции для загрузки данных из флэш-памяти).

person gbulmer    schedule 23.03.2012
comment
простите, какое "может"? Я заменил «может» на «должен», потому что «может» было неправильным. - person gbulmer; 23.03.2012

В дополнение к тому, что сказал другой:

  1. использование #define ничего не говорит о переменной. Define сам по себе не нуждается в них, но если вы сделаете что-то вроде int x = MY_DEFINE, он, конечно, будет использовать один, и он будет неконстантным.
  2. В некоторых цепочках инструментов/системах вы можете получить константные переменные в какой-то специальный раздел, который вы можете поместить во FLASH/ROM, обычно используя настраиваемые переключатели скрипта компоновщика/компилятора.
person dbrank0    schedule 23.03.2012