Этюды для начинающих: Память 1. Что и как не надо делать

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

brokly пишет:
Кстати, я почему то не нашел объяснения для чего нужны константы. Коллизия, объявлена как константа а храниться в ОЗУ. Хотя можем принудительно пихнуть ее во флешь, но тогда работать с ней придется с подвывертом (понимая, что это и почему).
Прежде всего const это спецификатор. И он сообщает что данная величина используется только для чтения. А уже потом компилятор решает как компактно и эфеективно ее разместить. Из этого не следует что const это обязательно константа.  Так же #define не делает что-то константой .  И вот еще мой вариант который мне больше нравится 

Cl_AAA AAA(/*константа*/12);

И это тоже константа, но без всяких const  и #define. Простенько и если надо можно на месте поменять.

const byte pin=/*пин A*/2;
#define pin1  /*пин B*/3

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

DetSimen пишет:

если в loop() ничо не вставлять, вызывается он примерно 50 тысяч раз в секунду. 

Да, нет, гораздо больше - 1,136МГц.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

qwone пишет:

brokly пишет:
Кстати, я почему то не нашел объяснения для чего нужны константы. Коллизия, объявлена как константа а храниться в ОЗУ. Хотя можем принудительно пихнуть ее во флешь, но тогда работать с ней придется с подвывертом (понимая, что это и почему).
Прежде всего const это спецификатор. И он сообщает что данная величина используется только для чтения. А уже потом компилятор решает как компактно и эфеективно ее разместить. Из этого не следует что const это обязательно константа.  Так же #define не делает что-то константой .  И вот еще мой вариант который мне больше нравится 

Cl_AAA AAA(/*константа*/12);

И это тоже константа, но без всяких const  и #define. Простенько и если надо можно на месте поменять.

const byte pin=/*пин A*/2;
#define pin1  /*пин B*/3

 

 

Все так спорно... так спорно... Нахрена константу "МЕНЯТЬ НА МЕСТЕ" (!!!) это же константа !!!!!!!

const и правда спецификатор, это не откровение, имхо, ни для кого :)

Компилятор ничего не решает, он разместит ее в озу :) 

И на десерт, понятие константа означает - постоянный, неизменный :)

И кстати... Cl_AAA AAA(/*константа*/12); - что это за бред?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

brokly пишет:
Все так спорно... так спорно... Нахрена константу "МЕНЯТЬ НА МЕСТЕ" (!!!) это же константа !!!!!!!

const и правда спецификатор, это не откровение, имхо, ни для кого :)

Компилятор ничего не решает, он разместит ее в озу :) 

И на десерт, понятие константа означает - постоянный, неизменный :)

И кстати... Cl_AAA AAA(/*константа*/12); - что это за бред?

Что спорно? В языке Си нет инструмента объявления только для образования констант. Или пользоваться макросом, или спецификатором const. Но и то и другое объявляет не только константы.

/**/
void func (const int a) { // <- a должна быть константой
  /*но только внутри функции,а снаружи это переменная*/
  const int b = 5; //<- константа , и распостранена только внутри функции
  /* в отличии от #define - который не возжно огаричить, если его уже объявили */
}
void setup() {
  10; 0x5; B0001;//<- это все 100% константы, а остальное может быть а может нет.:)
  int c = 5; //
  func(c);
  int const * const p = &c;  //Запрет изменять и хранимый в указателе "p" адрес,
}
void loop() {

}
/*Скетч использует 444 байт (1%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/

ПС:http://ci-plus-plus-snachala.ru/?p=1120

/**/
class Cl_AAA {
    const int a;
  public:
    Cl_AAA(const int a_): a(a_) {}
};
Cl_AAA AAA(/*константа*/12);//<- чего странного, Вы что не знаете, что константу можно прямо записать числом О_О
void setup() {

}
void loop() {

}
/*Скетч использует 494 байт (1%) памяти устройства. Всего доступно 32256 байт.
  Глобальные переменные используют 11 байт (0%) динамической памяти, оставляя 2037 байт для локальных переменных. Максимум: 2048 байт.
*/

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

qwone пишет:

/**/
void func (const int a) { // <- a должна быть константой
  /*но только внутри функции,а снаружи это переменная*/
 

Сами-то поняли что сказали?

а - формальный параметр, снаружи она не существует, а потому никак не может быть ни переменной, ни чем бы то ни было ещё.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы.... 

Я, када встретил в одном коде #define FALSE TRUE,  две недели пилъ беспробудно. 

Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали.  Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш. 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

DetSimen пишет:

В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. 

Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.

sirota
Offline
Зарегистрирован: 18.08.2015

qwone пишет:

 

const byte pin=/*пин A*/2;
#define pin1  /*пин B*/3

 

 

и что вы тут поменяли на лету и что такое "/*пин A*/2" и далее

ЕвгенийП пишет:

Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.

я не спец, но ни одного языка высокого уровня окромя убогово javascript  я не видел возможность изменения предопределенной константы. Есть только в C++ (за C не скажу) и производных возможность снять признак постоянства. Но обычно в жизни считается подобное мерой крайней и не культурной. Хотя сам по себе язык такое позволяет.

А ну и конечно случаи не корректной передачи данных внутрь вызываемых функций (когда передают как сами данные, так и казатель на них, а внутри рабоитают, если грубо, то с обратной стороны).

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

sirota пишет:

компилятор просто не даст этого

Чего не даст? Константу поменять? А кто его спрашивать-то будет? :)

sirota пишет:

убогово javascript

Фига се! Это про язык с динамическим полиморфизмом и прототипным наследованием? Боюсь, что использованное Вами прилагательное больше отражает уровень Ваших знаий о JavaScript, чем природу языка.

sirota пишет:

я не видел возможность изменения предопределенной константы.

В старом добром Фортране IV это была штатаная фича. Причём менялась константа как таковая (например 5 становилось равным 3 или там 10). И, повторяю, это была не особенность реализации, а штатная фича. В таком виде Фортран существовал десятилетиями. Ушло это только в новых стандартах, причём обычно есть опция "вернуть" для совместимости с миллиардами строк кода, написанных на Фортране.

sirota пишет:

 в жизни считается подобное мерой крайней и не культурной. 

Я бы сказал "говнокодом".

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Вообще, изначально в своей реплике я противопоставил #define - const, говоря о том, что такой прием, часто позволяет съэкономить оперативку, а иногда ускориться, и уже как на побочку намекнул на некую нестыковку самого определения константы и возможных с ней операций :) Естественно все это в приложении к ардуино.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

DetSimen пишет:

В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы.... 

Я, када встретил в одном коде #define FALSE TRUE,  две недели пилъ беспробудно. 

Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали.  Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш. 

Мелочи. Уже приводил тут примерчик из реального и не мелкого проекта, что-то типа так:

#if !defined( _MY_CONST_ )
#define if(p) if( (rand()%100>10) && (p) )
#endif

Вот это - точно засада..

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

Вот это - точно засада..

Ну, почему сразу засада. Если по жизни стояла задача: "Если p, то с вероятностью 0,1 выполнить ...", то конструкция как конструкция. Прокомментировать как следует и, когда станет не нужна, выбросить #undef'ом. Хотя, я бы делал это по-другому.

pridecom
Offline
Зарегистрирован: 07.07.2017

Привет. Вопросик.

Есть переменная 

double tm = 0 ;

в цикле loop ей присвоили значение в минутах работы системы

tm = ((millis()/1000)/60);

и выводим на экран.
lcd.print(tm ); 
 
Например 
110000 милисек это 110 сек или 1.83 минуты
Однако выводит почему-то 1.00 минуты, округляет обрезая до нулей гадина
что я делаю не так?
ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

pridecom пишет:

что я делаю не так?

Пытаетесь программировать на языке, которого не знаете и знать не хотите (ни одна нормальная книжка по языку Вами не прочитана).

Целочисленное деление в этом языке производится с отбрасванием остатка, каким бы он ни был. Результат всегда целый. Например, 200/200 и 300/200 и 399/200 - результат один и тот же, а именно - 1.

pmaster
Offline
Зарегистрирован: 23.05.2011

А как узнать размер стека в настоящий момент? 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

pmaster пишет:

А как узнать размер стека в настоящий момент? 

Указатель стека называется SP. Он доступен в любой момент. Т.е. запомните его в началеа потом посмотрите в нужной точке и, вычтя одно из другого, узнаете какой стек Вы уже накопили.

В принципе, вот в этой теме, в конце первого поста, есть программа Memory Explorer. Она печатает и стек, и кучу, и свободные куски.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Всем привет!

А что вы обычно делаете когда внезапно : Sketch uses ... (95%) of program storage space.

В проекте пара десятков .cpp & .h файлов, все внешние библиотеки отключил, где можно поставил пустые заглушки.

Но без внешних библиотек стало не сильно лучше ~50%, интересно как посмотреть какой именно свой модуль жрет flash? 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Вы дали слишком мало информации, чтобы можно было ответить конкретно. Но, в целом, если Вы не понимаете какой модуль отжирает, попробуйте

1. Назначить свой фолдер build
2. После компиляции посмотрите в него и во все его подфолдеры. Там будут файлы с названиями Ваших модулей (и библиотечных, и системных тоже) с расширением ".o" - это скомпилированные файлы модулей.

Вот и смотрите какой из них какого размера. Это не точно, но общее представление даст.

nik182
Offline
Зарегистрирован: 04.05.2015

У меня работает программа со 100% storage space. Специально менял порядок операторов, что бы уложить последние 2 байта. Никаких проблем.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Спасибо! тут всё просто : Sketch uses ... (91%) of program storage space. вот и вся информация.
Ее уже достаточно что-бы задуматься. 

В папочке \arduino_bulid_xxxxx\  всем-известные библиотеки  Wire,  SPI, RadioHead
Гораздо интереснее в папке \core
Там откуда-то взялись HardwareSerial.cpp.*, USBCore.cpp.* и IPAddress.cpp.*
100% нигде у меня они не подключены, и не могут быть подключены, интересно, где посмотреть кто их за собой тянет?

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Откомпилируйте вот такую программу

void setup(void) {}
void loop(void) {}

а потом посмотрите в ту самую папку.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

уже компилировал пустой проект, и обалдел от объёма  .o & .d файлов.

с другой стороны, всё это изобилие занимает 450 bytes (1%) of program storage space.

что подтверждает мои подозрения, что по объёму .o & .d файлов в build/libraries ничего определенного сказать не получится

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Не получится - это даст только общее предствление.

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

Вы представляете себе работу компилятора и линкера? Те, кто представляют, те никогда не ленятся лишний раз написать слово static, например.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Как раз static-ом надо пользоваться осторожно и только по-необходимости. Вы наверное опечатались в слове const.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Нет, я написал то, что хотел написать. 

Посмотрите на скетчи, опубликованные здесь на форуме. Если Вы где-то найдёте глобальную переменную или функцию, объявленную как static - это большая редкость. Между тем, если переменная или функция не вызываются из других файлов, нет никаких причин не объявить их статическими, ну вообще никаких. Люди этого не делают просто из лени, а большинство из непонимания возможных выгод от этого.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Но ведь под статические переменные память резервируется сразу и нет возможности использовать "временно неиспользуемую" память под сиюминутную нужду (большой буфер необходимо сформировать, например). Или таки это плюс, а не минус?

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Последнее использование static— глобальная переменная в файле кода. В этом случае использование staticуказывает, что исходный код в других файлах, которые являются частью проекта, не может получить доступ к переменной. Только код внутри того же файла может увидеть переменную (её область видимости ограничена файлом). Эта техника может быть использована для моделирования объектно-ориентированного кода, потому что она ограничивает видимость переменных и таким образом помогает избежать конфликта имен. Этот способ использования staticявляется пережитком Cи.

Женя про это написал.
sadman41
Онлайн
Зарегистрирован: 19.10.2016

А, ну теперь понятно. Я столько глобалов не создаю, чтобы прям запутаться в них (вообще редко создаю), поэтому статик только для сохранения значений внутри функции использовал (и подумал, что лажаю с ним, если не ставлю везде )). Ну и... паттернализм, вобщем - что всегда делаем, о том постоянно и думаем.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Совершенно верно.

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

А вот если она не статик, то компилятор не может её выбросить, т.к. вдруг она из другого файла используется? В этом случае её может выбросить только линкер.

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

Т.е. объявляя её static, мы помогаем оптимизатору.

Тоже касается и функций. Если функция глобальна и Вы не планируете использовать её из других файлов - не скрывайте этого от оптимизатора - объявите static. Он её может в inline засунет или, если Вы перестали её использовать, запросто вообще выбросит.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Большинство моих классов полностью статические, т.е. все поля и методы у них объявлены как static, всё что static const и более-менее крупное - объявлено как PROGMEM. Никаких #define для констант - только static const с контролем типов.

>Почему преимущественно статические классы ?
<А для того чтобы не создавать экземпляров, у меня на плате только один LCD-экран, одни RTC-часы и т.д. зачем мне дурацкие конструкторы, передающие номера пинов, запоминающие эти пины в оперативке(а именно так и происходит в большинстве библиотек), -хотя вся конфигурация известна на момент компиляции.

Но, бездумно тыкая везде static я забыл что элементы-то меню у меня динамически создаются и тут я профукал 78 байт оперативки на ровном месте, а таких мест десятки.

class RangeTranceive : public State {
     ...
     static char scr[screenSize][rowSize]; 
     ...
 }; 

p.s. а размеры функций можно посмотреть утилитой av-nm ( https://blog.benoitblanchon.fr/arduino-code-size-and-assembly/ ) просто обалденная штука, сортирует функции по величине и корректно отображает названия, очень рекомендую.