Malloc, куча, стек

Ну, по крайней мере мне это помогло. Оптимизатор иногда делает неочевидные вещи, смотришь потом дамп и ничего не понимаешь.

Да, спасибо, сейчас увы, занят, позже вернусь к этой теме

Ты прав. Учиться надо на управляемых примерах, ведь если следовать логике моего доброго друга, то нельзя учить будущих хирургов на трупах, так как пациент не орет и не дергается и не материт доктора . Что очевидно представляет “тепличный, упрощённый режим, который “на самом деле” никогда не используется

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

Возник теоретический вопрос: а функция/код - вообще , “обязаны” работать с опцией -О0? Есть ли какое-то правило на этот счёт?

Простите, можно пояснить вопрос?

Это когда с -О0 не работает, а с -О3 - работает.
Или это косяк в коде?

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

Если компилятор не позволяет добавлять опции в командную строку (как в Ардуино ИДЕ, например), то можно вот так сделать:

#  pragma GCC optimize ("O0") // выключить
ваша функция тут
#  pragma GCC optimize ("O2") // включить  (O3 - побыстрее, по скорости, Os - поменьше, по размеру, 07 если хотите поискать фантомные глюки в своей программе, 09 - если ищите глюки в GCC :)

Возможно, просто с -О0 - много памяти жрёт, потому и не работает.
А с ключом -О2 и выше -тот же код уже работает

Это сильное указание на какой-то косяк в коде. Но не 100 процентов, конечно

Тоже к этому склоняюсь.

Вообщем, надо мне ещё с этим вопросом самому “подразобраться”.
Пока не стоит занимать внимание почтенных…
Лучше позже спрошу более конкретно, если ворос останется

Ну там есть увеличение памяти, но оно не критичное.

К тому же в основном увеличивается размер кода, который и так на флешке лежит.

Спойлер

Обычно, кстати, наоборот - с O0 работает, а с O3 - баги лезут :). Переменная неинициализированная небось где-то. Разница между оптимизированным и неоптимизированным кодом зачастую вылазит именно в неинициализированных переменных (или неправильно инициализированных). Еще разница - в значениях на стеке. В O3 может повезло и на стеке лежит 0, а при O0 там лежит 0xffff ккой-нибудь. Ну это я все тоже отношу к неинициализированным данным, как классу ошибок

Ну если после компиляции выходной файл или данные озу на пределе, то конечно. В противном случае зачем в обще включать оптимизацию. Если всё уж в притык, то проще камень пожирнее взять, чем потом ловить глюки.

Спорный ответ. Если работать по классике и “скармливать” данные функции в виде копий - ДА, при -О0 локальные переменные компилятор аккуратненько уложит в стэк, причем даже те, которые и ложить нет надобности.
Между -О1 и -О2 особой разницы нет, стэковый фрейм не делается, -О3 и -Os компилятор “распихает” переменные по регистрам.
А если работать с указателями - то даже при -О0 стэковый фрейм будет “пустым” и память не будет расходоваться вовсе.
Можно вообще написать софт так, что для стэка нужно несколько байт.
Здесь разница в том, кому писать - AVR или STM32.
В STM32 два стэка а в AVR он один и общий.
В STM32 при входе в вектор ядро само сохраняет несколько регистров + LR адрес возврата. AVR так делать не умеет и надо писать самому.
Если делать все через указатели - 10 байт (uint32_t) будет достаточно для стэка.

шо ты куришь? какие локальные переменные в какой стек? Услышал слово стек и плюешься им где ни попадя. При -О0 как раз наоборот, попытается оставить в регистрах, если есть свободные.

ну че пристал, человек изучил указатели и перешел к стеку.

Я не курю.
Тебе показать стэковый фрейм?
Без проблем…

та я не о том. откуда информация, что при разных флагах оптимизации будет приниматься решение по размещению переменных в стеке или регистрах? Если, например, десяток регистров ещё свободны, то что, получается компилятор будет один хрен пихать в стек?

ДА(!!!) Будет ПИХАТЬ.
Давай я попозже за большой компуктер засяду и покажу на реальном примере. Правда это будет STM32. На AVR там чуть по другому компилятор отрабатывает, потому что в STM32 нет индексных регистров X, Y и Z.
На STM32 любой регистр может быть индексным.

че орать? если проверял, то ок, спору нет. я не проверял режимы оптимизации, потому не знаю.

Проверил только что пару флагов. Чет ни при каком в стек ничего не кладет при свободных регистрах. Просто переписало с r16 в r17 и выплюнуло в порт.

а если попытаться занять r16-r31, то компилятор использует r0-r15. Короче, чтобы дело дошло до хранения лок. переменных в стеке, надо занять все регистры.

А попробуй несколько переменных (три) запихать в функцию сначала как копию, потом как указатели.
Здесь будет большая разница с архитекрурой STM32. И компилится будет по разному, я писал уже выше причину. На STM32 команд с адресацией гораздо больше, чем в AVR и адрес у нее весь целиком “влазиет” в регистр, а у дуни регистр 8-и битный и пара будет адресовать только 64кб максимум.
Не будем только про “биты_раком” вспоминать, плз)