Этюды для начинающих: Память 2. Статические переменные.

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

ptr, писал: "Во-первых, большинство архитектур поддерживают .."

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

Arduino Due с ее ARM уже не Ардуино? А там адресация c ограниченным смещением очень активно используется. А смещение то всего, в зависимости от ситуации, от 255 до 4095 байт.

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

ptr .. и снова вы сваливаетесь на "программист === дурак": "А программист не способен постоянно безошибочно контролировать, какая функция TS (Trhread Safe), а какая нет." Напомню постулат из психологии: "Каждый всегда судит о других по себе любимому"...

Напомню народную мудрость: "Не ошибается только тот, кто ничего не делает"

Я ошибаюсь часто, каждый день по многу раз. То SQL на мой запрос отругается, то компилятор на мой код, то кто-то из моей команды укажет мне на мою ошибку. Каждый день! Я дурак по-вашему?

А проблема с Not Thread Safe функциями опасна тем, что она может не проявиться ни на этапе отладки, ни на этапе тестирования, а вылазить только у нескольких клиентов, да и то, в момент пиковых загрузок раз в месяц. Попробуй поймай потом такую багу.

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

Тут программирование микроконтроллеров! Ну не бывает тут "больших приложений"! :)

Не согласен. Несколько лет активно занимался программированием Z80. Часто, всего с 16Кб памяти. Иногда, с 48Кб. На все, и на программу и на данные. В основном, на ассемблере.

Например, делали прошивку Z80 для принтера. Вчетвером. Я занимался управлением непосредственно двигателями и иголками печатающей головки и обменом по Centronix, предоставляя функции для более высокого уровня. Девочка у нас рисовала шрифты и оформляла документацию. Другой парень занимался интерпретацией ESC команд принтера на C. Третий - железом. Исходников было свыше сотни тысяч строк, если считать загружаемые шрифты и калибровочные данные для разных игольчатых головок. У них не было обратной связи, а время на выход и убирание иголки плавало даже у разных партий, не то что у разных производителей.

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

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

Ptr, 2 момента:

1. Тут даже Мега2560 - большая редкость, полистайте форум. В лучшем случае 328p, а то и вовсе тиньки используются. Что уж за Due говорить!

2. Мы все ошибаемся, и я тоже не исключение. Точно также "по нескольку раз в час". :) Но, я не делаю из этого никакой проблемы, ибо это нормально. И отказываться от эффективных способов программирования и уж тем более СОВЕТОВАТЬ другим что "так не надо" - не могу себе позволить. Слишком велико отличие подходов к программированию микроконтроллеров от "общих" методик. И цена говнокода - слишком высока на мой взгляд: вынужденный, по неумению переход на следующие линейки по мощности/производительности там, где это вовсе ни разу не востребовано.

Да собственно, сами посмотрите коды от того же Dimax-а для тинек! Одни сплошные регистровые глобалы.. :)

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

Да и ещё: относительно большими я привык называть проекты от 5-10 миллионов строк кода. Так, ежели вчё. :)

Ну и "взрослый подход" рекомендован даже для относительно маленьких проектов .. хотя бы в части "самодокументирования" .. порой, без документирования, даже через пару месяцев смотришь на код и не можешь понять "а нафига так наворочено" .. тут как говорится "размер не имеет значения". :)

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

Архат! Вы удивительный человек.

Евгений написал, что люди УЖЕ имеющие квалификацию не являются целевой аудиторией.

Учиться же следует просто правильному програмированию, не програмированию микроконтроллеров, или програмированию суперкластеров, а ПРОСТО грамотному програмированию.

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

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

А ПОТОМ, когда человек начнет писать сам, он уже САМ разберется, где можно экономить память и скорость.

---------------------------------------------------------

Когда-то давно я решил овладеть новым для себя навыком сварки оптоволокна. Меня и жену (которая потом много лет этим занималась) учил старый дедушка из бывшего ВНИИКП. Так вот его любимая фраза была такая: "Ты делай хорошо, плохо - оно само получится.". В итоге потом, когда было нужно, супруга варила в стойке, когда помошник держал сварку на вытянутой руке и при свете налобного фонарика. НО ПОТОМ. А сначала нужно было научиться ПРАВИЛЬНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ОПЕРАЦИЙ.

findeler
Offline
Зарегистрирован: 08.03.2016

А есть вариант статической переменной для каждого вызова функции.  То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для  этого вызова.

Нечто средние между static и обычной переменной  внутри функции.

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

findeler пишет:

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

Приведите пример, пожалуйста, а то я не понял что Вы имеете в виду.

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

1. Тут даже Мега2560 - большая редкость, полистайте форум. В лучшем случае 328p, а то и вовсе тиньки используются. Что уж за Due говорить!

И что с того? Если редкость, то значит уже "такого не бывает"? И код на Due нельзя переносить с AVR? По мне так вполне нормальный подход. Когда не влазишь в 328, переходишь на 2560. Не устраивает 2560, переходишь на ARM. И необходимость переписывать при этом переходе полкода - признак недальновидности.

И только не надо мне говорить про "оптимизацию", чтобы влезть в 328 или 2560. Это оправдано только на тиражах в сотни экземляров. Для примера, себестоимость часа работы программиста ~2000 рублей. Даже если не платить вообще налоги и выдавать зарплату всю в конверте, будет ~1000 рублей. На руки тогда хотя бы 80 тыс. в месяц получиться, если урезать до безобразия накладые расходы, капитальные вложения, management fee и норму прибыли. При стоимости Due порядка 800 рублей, лишняя неделя работы программиста окупится только при тираже свыше 60 единиц.

И вообще, смешно говорить о стоимости МК, когда в стоимости проекта, при любых раскладах, она составляет единицы процентов. Выбирается тот, на котором быстрее можно реализовать проект.

Кстит, ESP8266, стоимостью, как Arduino Nano вполне себе 32-х разрядный 80МГц (до 160МГц) процессор. Так что при нехватке памяти или быстродейстия переход на него вообще не приведет к дополнительным затратам на комплектующие.

Цитата:

2. Мы все ошибаемся, и я тоже не исключение.

А значит, Вы способны по ошибке вызвать Not Thread Safe функцию (свою или библиотечную) в многопоточном проекте, что приведет потом к долгим часам поиска этой баги. Что и требовалось доказать.

 

ptr
Offline
Зарегистрирован: 28.05.2016

findeler пишет:

А есть вариант статической переменной для каждого вызова функции.  То есть завершение функции не ведёт к уничтожению переменной, её значения сохраняются, но только конкретно для  этого вызова.

Нечто средние между static и обычной переменной  внутри функции.

Если имелось в виду, что для каждой нити будут свои статические переменные, то в C это не возможно, да и бессмысленно. Сама идеология нитей подразумевает, что у них общее, а не раздельное адресное пространство. А если речь о параллельно выполняющихся разных задачах, то у них, по определению, у каждой свои статические переменные.

 

findeler
Offline
Зарегистрирован: 08.03.2016

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

Приведите пример, пожалуйста, а то я не понял что Вы имеете в виду.

Функция опрашивает датчик за каждый вызов 1 измерение. В ней через static реализован массив старых значений. Поскольку функция не только опрашивает, но и проводит анализ. Каждый вызов это измерение и запись в следующий эллемент массива. 

То есть пока функция всего одна всё будет корректно.

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

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

И что Вы предлагаете? Какой механизм использовать?

findeler
Offline
Зарегистрирован: 08.03.2016

ptr пишет:

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

Парралельно да. Ну что бы не городить огород было бы удобно. static не для всех вызовов функций, а для каждого вызова свой.

findeler
Offline
Зарегистрирован: 08.03.2016

ptr пишет:

 Это оправдано только на тиражах в сотни экземляров.

Поправлю, даже тысяча не особо отбивает.

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

findeler пишет:

ptr пишет:

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

Парралельно да. Ну что бы не городить огород было бы удобно. static не для всех вызовов функций, а для каждого вызова свой.

Мне дико неловко, но Вы про объектное програмирование слышали?

То, что Вы хотите - называется объект. Для каждого вызова - новый, Вы не поверите! И все переменные у него свои и никуда не деваются между обращениями к методам...

Еще раз - простите, просто не мог не поглумиться.

 

findeler
Offline
Зарегистрирован: 08.03.2016

wdrakula пишет:

Мне дико неловко, но Вы про объектное програмирование слышали?

Слышал конечно. Но что вы предлагаете. Переводить всё в объекты? Мне только для этих датчиков и нужен такой механизм, для всего другого не требуется.

Навыка ООП у меня нет, да и нужен ли он для таких простых вещей.

ptr
Offline
Зарегистрирован: 28.05.2016

findeler пишет:

Функция опрашивает датчик за каждый вызов 1 измерение. В ней через static реализован массив старых значений. Поскольку функция не только опрашивает, но и проводит анализ. Каждый вызов это измерение и запись в следующий эллемент массива. 

То есть пока функция всего одна всё будет корректно.

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

#define ERR_SUCCESS             0
#define ERR_NULL_POINTER       16
#define ERR_NO_MEMORY          32

#define SENSOR_DATA_ARRAY_SIZE  8

typedef struct sensor_data_st {
  int sensor_no;
  int *data_array;
} sensor_data_t;

int get_sensor_data(sensor_data_t *sensor_data)
{
  int i;

  if (!sensor_data) return ERR_NULL_POINTER;
  if (!sensor_data->data_array)
  {
    sensor_data->data_array=malloc(SENSOR_DATA_ARRAY_SIZE*sizeof(int));
    if (!sensor_data->data_array) return ERR_NO_MEMORY;
  }
  ....
  sensor_data->data_array[i]=get_sensor_status(sensor_data->sensor_no);  
  ...
}

Перед вызовом функции указываем номер датчика в sensor_no. Не забываем освободить выделенную память в data_array, если она больше не нужна.

ptr
Offline
Зарегистрирован: 28.05.2016

wdrakula пишет:

Мне дико неловко, но Вы про объектное програмирование слышали?

Ваше дело, но в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.

ptr
Offline
Зарегистрирован: 28.05.2016

Напортачил в коде. Исправил по месту.

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

PTR! Это же не Вам написано было, а новичку.

Да  и по сути, Вы вдруг Архата напомнили. Он хороший програмист, как бы не ругался с Евгением, но у него пунктик на тему ООП. Он его органически не переносит. Что не может не вызывать добрые усмешки.

Всякому овощу - свой фрукт, как говорят. ;)

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

findeler пишет:

wdrakula пишет:

Мне дико неловко, но Вы про объектное програмирование слышали?

Слышал конечно. Но что вы предлагаете. Переводить всё в объекты? Мне только для этих датчиков и нужен такой механизм, для всего другого не требуется.

Навыка ООП у меня нет, да и нужен ли он для таких простых вещей.

если Вы не ограничены пока памятью для размещения кода - то да, конечно переводить.

Вы - новичек и отлаживать ООП - гораздо проще из-за читаемости.

К тому же объект можно отладить отдельно и быть в нем уверенным, а потом включать в Вашу котельную.

findeler
Offline
Зарегистрирован: 08.03.2016

ptr пишет:

Перед вызовом функции указываем номер датчика в sensor_no. Не забываем освободить выделенную память в data_array, если она больше не нужна.

Спаибо конечно, но именно от этого я и хотел избавиться.

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

Просто подумал, может  есть более простое решение.

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

ptr пишет:

в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.

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

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

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

findeler, ну если не хотите ООП, есть ещё 100499 способов. Например, можно завести двумерный массив: по одному измерению идут хранимые параметры, а по другому - номер датчика. И никакой путаницы.

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

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

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

+1! И даже глобалы хороши, если проект на один-два экрана помешается.

findeler
Offline
Зарегистрирован: 08.03.2016

wdrakula пишет:

Вы - новичек и отлаживать ООП - гораздо проще из-за читаемости.

К тому же объект можно отладить отдельно и быть в нем уверенным, а потом включать в Вашу котельную.

У меня нет навыка в ООП, где можно кратко ознакомиться с принципами и механизмами реализации.

findeler
Offline
Зарегистрирован: 08.03.2016

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

findeler, ну если не хотите ООП, есть ещё 100499 способов. Например, можно завести двумерный массив: по одному измерению идут хранимые параметры, а по другому - номер датчика. И никакой путаницы.

У меня структура со всеми возможными состояниями и значениями всего и вся. Но просто подумал что есть возможность легко вынести наружу.

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

Ну, массивы структур тоже никто не отменял :)

findeler
Offline
Зарегистрирован: 08.03.2016

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

Ну, массивы структур тоже никто не отменял :)

Типа того. Только в структуре сразу создан двухмерный массив под все возможные  датчики.

ptr
Offline
Зарегистрирован: 28.05.2016

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

ptr пишет:

в условиях жестких требования к быстродействию и объему занимаемой памяти, использовать объектно-ориентированное программирование не рекомендую.

"вот это использовать нельзя, а вот это нужно"

"Каждый инструмент хорош и очень хорош, когда применяется умело и именно для тех работ, для которых создан.".

Во-первых, я сказал "не рекомендую", а не "нельзя". Можно, конечно, но надо понимать при этом, что за все надо платить. И цена за удобство ООП - потеря в производительности, увеличение размера кода и сложности в отладке, при наличии множественных наследований с перегрузками.

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

То есть, обожая QT, я для ядра Linux С++ даже не подумаю предложить )

 

ptr
Offline
Зарегистрирован: 28.05.2016

wdrakula пишет:

+1! И даже глобалы хороши, если проект на один-два экрана помешается.

Глобальные переменные ничем не заменить для обработчиков прерываний. Так что они, безусловно, необходимы. Просто их количество не должно расти неконтролируемо по мере развития проекта.

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

wdrakula пишет:
.. Евгений написал, что люди УЖЕ имеющие квалификацию не являются целевой аудиторией. Учиться же следует просто правильному програмированию, не програмированию микроконтроллеров, или програмированию суперкластеров, а ПРОСТО грамотному програмированию. ...

Ну .. тут много удивительных людей .. видимо место такое. Я уже неоднократно писал и могу написать ещё 100500 раз, что учить надо не абстрактному "правильному программированию" сферических коней в вакууме, а оптимальному программированию, тому кторое дает выигрыш И по размеру кода И по скорости его исполнения. Как раз новички - и есть та самая целевая аудитория, за правильное обучение которой я и ломаю копья тут. Чего Евгений - в корне отказывается признавать.

.. а Вы (удивительные люди) предлагаете учить их "абстрактному управлению авто" .. а то что Автобус, КАМАЗ с прицепом и велосипед с самокатом в корне отличаются по способам и методам управления .. это они "потом познают". То бишь тормозить пяткой на самокате - самое то, но вот мало кому придет в голову делать это на КАМАЗе .. а вы предлагаете ИМЕННО ТАКОЙ ПОДХОД.

Чего тогда удивляться задаваемым тут вопросам типа "где гидравлический усилитель руля на этом самокате?" :)

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

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

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

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

 

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

Ваш выбор есть тавтология. Ибо не определно что значит "правильно". Потому как правильно - оно сильно по-разному (КАМАЗ, Автобус, лисапед, самокат, и т.д.):

1. Десктопное программирование "офисных" приложений. Как правило достаточно объемные проекты (скажем 1С-зарплата) .. есть свои критерии правильности, в частности модульность кода опирающаяся на развесистый ООП. Да, тут повальное использование глобалов (руление наклоном корпуса) есть зло.

2. Десктопное программирование "игровых" приложений. Как правило это в основном графика и звук .. и тут уже несколько иные критерии "правильности". Попробуйте реализовать какой-нибудь Дуум на базе иерархии классов ..

Это как-бы "общее программирование" .. и то оно РАЗНОЕ.

3. Программирование баз данных.SQL, оно же реляционная алгебра. Или то что хорошо С-шнику - смерть скульщику. а равно наоборот. Мозг требуется выворачивать на изнанку переходя от С к SQL .. ибо "циклов тут нет как факта". Я бы хотел посмотреть на реализацию сортировки выборки по приличной табличке и набору из 10-ка параметров "правильными" С-шными методами .. точно "возьмете" такого? Боюсь что нет. :)

5. Программирование микроконтроллеров .. этот форум. То, что должно начинаться словами: "забудьте всё чему вас учили сферические преподаватели вакуума". Ибо "тормозить пяткой" - наше фсё.

.. а Вы как раз РАТУЕТЕ за единый "правильный" подход .. а я даже малую часть разновидностей программирования не перчислил ..

Мне это напоминает старый анекдот, с концовкой: "А когда они прыгать с вышки научатся, мы им воды в бассейн нальем".

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

.. а Вы как раз РАТУЕТЕ за единый "правильный" подход .. а я даже малую часть разновидностей программирования не перчислил ..

Мне это напоминает старый анекдот, с концовкой: "А когда они прыгать с вышки научатся, мы им воды в бассейн нальем".

Я же объяснил почему я так считаю: "обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся". И у меня уже был не раз печальный опыт, когда, вроде бы хорошего программиста, приходилось увольнять. Так как с его кодом через год он уже и сам не мог работать, не то что остальные.

А программировать на проектах приходится что угодно. Например, для РосСетей (ТулаЭнерго) от сложных хранимых процедур SQL и навороченных сервисах на C# на мощных серверах до контроллеров Smart Grid, собирающих события и показания с приборов учета по PLC и отсылающих их по GPRS. А уж что только не программировали для Почты России, тут вообще не перечислить.

Если бы анекдот... Тут как на дороге. Не важно, на Камазе или на велосипеде - ПДД для всех одни.

 

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

Ибо не определно что значит "правильно". Потому как правильно - оно сильно по-разному (КАМАЗ, Автобус, лисапед, самокат, и т.д.):

Я же явно сказал! "Правильно" - это соблюдая ряд правил, которые позволяют минимизировать количество ошибок при написании программы. И эти правила могут быть разными, для разных языков, но для С они одинаковы хоть на мэйнфрейме, хоть на МК.

 

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

Или то что хорошо С-шнику - смерть скульщику. а равно наоборот. Мозг требуется выворачивать на изнанку переходя от С к SQL .. ибо "циклов тут нет как факта".

Простите, улыбнуло. Любой SELECT/INSERT/UPDATE уже есть цикл по сути. Я уж не говорю об операциях с курсорами и явными организациями циклов в том же T-SQL или PL/SQL. Я программирую и на C и на SQL. Без всякого выворачивания мозга )

Цитата:

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

А ORDER BY для чего? Или вы про то, как это SQL сервер делает? Я думаю, обычным quick sort с последующим слиянием отсортированных фрагментов.

Цитата:

и набору из 10-ка параметров "правильными" С-шными методами .. точно "возьмете" такого? Боюсь что нет. :)

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

 

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

Я про то, что типовой вопрос С-шника, программирующего СУБД на SQL это "а как тут цикл организовать?" .. нету циклов в реляционной алгебре от слова "совсем" .. и разные "курсоры" и прочие "навороты" в конкретных релизах - есть КОСТЫЛИ тем, кто не может решать задачи реляционной алгебры .. то бишь "вывернуть мозг" от алгоритмическго языка к реляциям. Равно как и явных (циклических) сортировок нет. Есть один единственный ORDER BY и что там лежит под ним, и каким набором циклов реализован SELECT .. реляционщику "по-барабану". И то, что "правильно" у реляционщика .. ровно наоборот у С-шника.

А ваш выбор "способный писать правильно", в смысле "без ошибок" .. как раз и есть ОПТИМАЛЬНОЕ программирование с использованием красивых решений и уже "типовых" алгоритмов. То есть - тавтология.

И, перечитайте себя: "я не рекомендую использовать глобальные переменные" .. это по-вашему правильно тут, в программировании микроконтроллеров? Да у Вас зачастую памяти даже под стек "не хватит" организовать все на вызовах! И после этого вы побежите покупать "побольше и помощнее" .. так и НЕ научившись программировать микроконтроллеры.

Это я и называю "а потом мы вам водичку нальем", а Вы пока потренируйтесь прыгать в пустой бассейн. :)

"Удивительные люди! Чесслово!"

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

Да у Вас зачастую памяти даже под стек "не хватит" организовать все на вызовах!

А пруф где? Или хотя бы аргументы?

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

1. Загрузить ее адрес в регистр X, Y или Z, а только потом обратиться к переменной.
2. Загрузить в регистра X, Y или Z начало сегмента статических переменных и адресоваться через смещение от регистра ко всем глобальным переменным не перезагружая адрес. Но это пройдет только в том случае, если общий объем глобальных переменных меньше 64 байт.

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

Итого, сэкономив 2 байта в стеке на адрес переменной, увеличиваем расход памяти программ, да еще и понижаем быстродействие. И это при том, что расширить оперативную память для AVR возможностей полно, а программную - нет.

 

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

Вот, вот .. начинается. :) Вы случаем AVR с пиками не попутали? Тут, по секрету, есть прямая адресация глобала из команды. Все 64кб адресов и 2 слова программы (1 команда, 2 такта). Может, все-таки изучить матчасть, вместо предложения обучения "сферическим коням в вакууме"? .. это собственно и есть то, про что пишу: детскому самокату не требуется гидравлика. Она ему ПРОТИВОПОКАЗАНА. :)

ssss
Offline
Зарегистрирован: 01.07.2016

Мдя. ptr, вы действительно верите в чушь которую вы тут выложили или вы просто неистово троллите Arhat109-2?

Но по любому, попкорном стоит запастись. ))))))))

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

есть прямая адресация глобала из команды

Пруф?

Мне стало жутко интересно, как в 16-ти битную команду удалось впихнуть и код команды и 16-ти битный адрес )

ptr
Offline
Зарегистрирован: 28.05.2016

ptr пишет:

Пруф?

Мне стало жутко интересно, как в 16-ти битную команду удалось впихнуть и код команды и 16-ти битный адрес )

Уточню, меня интересует именно 16-ти битный вариант команды, так как 32-х битный доступен вовсе не во всех AVR.

А если речь идет именно о 32-х битной команде, то это уже потеря двух байт в программной памяти, ради выигрыша 2 байт в стеке )

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

Ок. Давайте по порядку. Ваш совет "глобалы == зло" подразумевает для AVR и микроконтроллеров "в целом" (есть конечно нюансы, но несущественно):

1. "не хватит стека". Аргументы простые: вызов функции с параметром, это а) подготовка параметра для укладки на стек - 1 команда с ПРЯМОЙ адресацией для загрузки регистра для байта, 2 команды для int и 4(ЧЕТЫРЕ) команды для long. Далее, имеем ЕЩЁ 1 команду для каждого байта для укладки параметра на стек. Итого для long имеем 8(восемь!) дополнительных команд.

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

Среднее количество параметров в функциях = 3.5, средний используемый тип 2.5 байта. Для новичков, в целях перестраховки берем 4 байта, хотя бы потому, что любимый millis() возвращает long. Итого, только на вызов функции тратится 3.5 * 4 = 14 байт стека и 3.5*16/32 <24>(в среднем) = <84> байта флеша для кода подготовки вызова. Кроме этого, функция имеет локалы .. их среднее количество также 3.5, и для типа long (напомню - это любимый тип всех начинающих) на регистрах будет только 1 переменная .. итого 2.5 * 4 = 10 байт плюсом из стека "долой". Ещё кроме этого, средняя функция сохраняет 3-4 (long!) регистра из пула "локальных" от предыдущего вызова .. пусть будет ещё пара байт.

Итого, средняя функция "программирования без глобалов" тянет на вызов 14 + 10 + 2 = 26 байт стека ПОМИМО хранения точки возврата. Плюс дополнительное время исполнения для примерно 50 команд из которых около трети в 2 такта.

Соответственно, "стека не хватит" определяется просто: делим имеющееся пространство стека на примерно 20-30 и смотрим допустимую глубину вложения вызовов рекомендуемого вами и автором опуса "ООП подхода". И это для средних, относительно простых функций. В случае "тяжелого кода" от новичка (типа классов Serial, Print и др.) этот показатель можно ускорить как миниум вдвое.

Неужели такую банальщину надо расписывать специалистам, берущимся ОБУЧАТЬ новичков?!?

Аналогично разбираются и ваши возражения предыдущего поста. Лично меня Вы уже смогли удивить и сильно .. :)

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

Да, кстати. Я ещё опустил рассмотрение вопроса ВОЗВРАТА результата функций обратно в вычисление и .. память. Так что, для "безглобального программирования микроконтроллеров" всё становится настолько печальным, что в пору бежать за "следующим поколением".. от неумения и догматического применения "рассово-правильного" подхода. :)

На самом деле "правилен" только один подход: оптимальное программирование. И оно .. РАЗНОЕ для каждого отдельного случая: SQL, десктоп, игры, сервера, транспьютеры и .. микроконтроллеры.

И до тех пор пока люди, берущие на себя ПРАВО ОБУЧАТЬ ДРУГИХ не начнут учить ХОРОШЕМУ .. надо чтобы хоть кто-то их останавливал в их стараниях учить плохому.

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

1. "не хватит стека". Аргументы простые: вызов функции с параметром, это а) подготовка параметра для укладки на стек - 1 команда с ПРЯМОЙ адресацией для загрузки регистра для байта, 2 команды для int и 4(ЧЕТЫРЕ) команды для long. Далее, имеем ЕЩЁ 1 команду для каждого байта для укладки параметра на стек. Итого для long имеем 8(восемь!) дополнительных команд.

Не понял, мы перешли к обсуждению 32-х битных МК? При чем тут long? Если включить мозги, то вместо кучи глобальных и статических переменных, кроме одной глобальной, необходимой обработчикам прерываний, у нас будет одна переменная, указатель на которую мы и будем передавать вызываемым функциям. Handle это принято называть.

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

 

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

ptr пишет:

чтобы не позорить оппонента.

Даже не пытайтесь. Лучше его самого это никто не сделает.Помните классику: "Советы космического масштаба и космической же глупости, а сами наелись зубного порошку третьего дня". Это как раз про Вашего визави:)

ptr
Offline
Зарегистрирован: 28.05.2016

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

Даже не пытайтесь. Лучше его самого это никто не сделает.Помните классику: "Советы космического масштаба и космической же глупости, а сами наелись зубного порошку третьего дня". Это как раз про Вашего визави:)

Похоже пора завязывать, а то оппонент сейчас еще скажет, что одной глобальной переменной для всех обработчиков прерываний не хватит )

Причем с его страстью к оптимизации совершенно не ясно, почему он решил передавать параметры через стек, а не через регистры, что GCC вполне позволяет.

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

ptr, я заметил что не поняли. Ну да ладно .. со временем придет и понимание.

Речь за типовые решения новичков, которые мало пользуются указателями в силу слабого опыта. И напрямую применяют огульные рекомендации от "сферическими гуру", что называется "на веру". А равно "типовые библиотеки", писанные как правило программистами "общего профиля" .. то бишь для "сферических коней в вакуумах", один набор иерархии Serial чего стоит ... Вы полистайте форум таки.. :)

ptr
Offline
Зарегистрирован: 28.05.2016

Arhat109-2 пишет:

Речь за типовые решения новичков, которые мало пользуются указателями в силу слабого опыта.

Программировать на C без использования указателей невозможно. Даже

Serial.println ("Hello World!");

уже использование char *

И в третий раз повторю, в том числе и про новичков:

"Обучить оптимизации качественно написанного кода я смогу, а вот заставить писать код качественно, так что бы минимизировать количество ошибок в программе, мне уже вряд ли удастся"

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