реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> [Вроде решено] Массив указателей на функции. Указатель на массив
jcxz
сообщение Feb 1 2017, 14:30
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 3 292
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(demiurg1978 @ Feb 1 2017, 16:18) *
Если честно, немного извращенно. Прототреды и то проще. Еще проще написать функции линейно, и вызывать их по указателю. Состояние - ссылка на нужную функцию. И никаких трат на сохранение-восстановление контекста.

Понятно когда таких состояний мало - я тоже не использую такой метод. Я же сразу говорил - это для сложных автоматов оправдано.
Когда состояний много, когда переходы между состояниями по разным условиям.
А особенно - если представьте:
Нужно чтобы после состояния S1 выполнялось несколько состояний S10-S11-S12 с последующим возвратом в основной поток к S2.
И такая-же последовательность нужна после скажем S3.
С классическим подходом (функциями или switch/case) придётся городить огород с сохранением переменной состояния автомата в отдельной переменной и восстановлением её потом.
Здесь же всё просто - просто пишем функцию. И всё.
То же самое - циклы с циклическим изменением состояний S1-S2-S3-...S1-.... Опять при таком подходе получается всё много нагляднее и проще чем классически.
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Feb 1 2017, 14:45
Сообщение #32


Местный
***

Группа: Участник
Сообщений: 320
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Я единственный раз использовал дополнительную переменную-состояние. Next_State. И только из-за того, что получались одинаковые куски кода. Как-то зашел разговор о культуре программирования. Я решил перелопатить код в соответствии с перечисленными участником форума правилами. В итоге перематерился. По сути я не программой занимался, а окультуриванием кода. Гламурность наводил. В особенности меня порой убивает запрет на GOTO. Хотя и понимаю, что GOTO порой опасно использовать.
Если где-то возникают трудности, значит нужно пересматривать подход в целом. Это правило меня никогда не подводило.
Честно сказать, я не программист в чистом виде. Увлекался электроникой, в определенный момент решил взяться за изучение МК. Так получилось, что моим выбором стали AVR-ки. Начинал с асма. На си переполз 3-4 года назад.

Сообщение отредактировал demiurg1978 - Feb 1 2017, 14:49
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Feb 2 2017, 07:52
Сообщение #33


Гуру
******

Группа: Свой
Сообщений: 2 659
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(jcxz @ Feb 1 2017, 15:58) *
Получили линейный, хорошо читаемый код.

Немного спорно.
А при наличии нескольких задач-автоматов SwitchStack() перестает быть симметричной.


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
jcxz
сообщение Feb 2 2017, 09:38
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 3 292
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Dog Pawlowa @ Feb 2 2017, 09:52) *
А при наличии нескольких задач-автоматов SwitchStack() перестает быть симметричной.

В смысле? Если нужно несколько независимых автоматов - для каждого свой стек и всё то же самое. В SwitchStack() просто добавится аргумент - указатель на рабочую переменную/стек.
Ну или своя SwitchStack() для каждого автомата.

Цитата(demiurg1978 @ Feb 1 2017, 16:45) *
Я единственный раз использовал дополнительную переменную-состояние. Next_State. И только из-за того, что получались одинаковые куски кода. Как-то зашел разговор о культуре программирования. Я решил перелопатить код в соответствии с перечисленными участником форума правилами. В итоге перематерился.

Это же тема - изначально про случаи сложных автоматов. Для простых достаточно switch/case.
А вот в случае сложных автоматов (а тем более если в них есть повторяющиеся или циклические участки) мой метод значительно упрощает код, он становится легче для анализа и отладки. Значит и матюкаться при его редактировании/отладке приходится меньше.
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Feb 2 2017, 09:56
Сообщение #35


Местный
***

Группа: Участник
Сообщений: 320
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Цитата(jcxz @ Feb 2 2017, 15:38) *
А вот в случае сложных автоматов (а тем более если в них есть повторяющиеся или циклические участки) мой метод значительно упрощает код, он становится легче для анализа и отладки. Значит и матюкаться при его редактировании/отладке приходится меньше.

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

Сообщение отредактировал demiurg1978 - Feb 2 2017, 09:56
Go to the top of the page
 
+Quote Post
jcxz
сообщение Feb 2 2017, 13:19
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 3 292
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(demiurg1978 @ Feb 2 2017, 11:56) *
Хотелось бы посмотреть реальный пример, который не жалко выложить на обозрение и который показывает причину, почему реализовано именно такое решение.

Причины у всех свои. Кто захочет - тот применит. Я тут никого не заставляю. Всё уже более чем разжёвано.
И почему такое решение не может быть реализовано?? Вариант с switch/case при кол-ве состояний >=20 много хуже получается и это, имхо, очевидно.
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Feb 2 2017, 14:26
Сообщение #37


Местный
***

Группа: Участник
Сообщений: 320
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Цитата(jcxz @ Feb 2 2017, 19:19) *
Вариант с switch/case при кол-ве состояний >=20 много хуже получается и это, имхо, очевидно.

В этом случае никто не спорит. И я сам об этом сказал. Что при большом кол-ве состоянии switch-case нечитабелен. Использую функции и индексный переход.
В вашем же случае я хотел посмотреть причину применения вашего подхода. Эти переходы по состояниям. Так сказать, наглядный реальный пример.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Feb 2 2017, 15:07
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 3 292
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(demiurg1978 @ Feb 2 2017, 16:26) *
В этом случае никто не спорит. И я сам об этом сказал. Что при большом кол-ве состоянии switch-case нечитабелен. Использую функции и индексный переход.
В вашем же случае я хотел посмотреть причину применения вашего подхода. Эти переходы по состояниям. Так сказать, наглядный реальный пример.

Ну например - использовал такой метод в ISR осуществляющем приоритетный арбитраж доступа к нескольким микросхемам (FLASH, FRAM) висящим на шине SPI, и управляющем транзакциями
(старт/стоп DMA-пересылок) записи, чтения к этим микросхемам по запросам от нескольких пользовательских каналов. Каждая транзакция состояла из нескольких шагов (подать команду разрешения записи, стартовать передачу блока, завершить обмен, опросить статус чипа и т.п.), которые разбивались на ещё более мелкие шаги. Эти транзакции собирались в ещё более крупные пакеты операций. Каждый такой уровень - это отдельный автомат со своей переменной состояния. Эти автоматы реализовал switch/case-ом.
В этом-же ISR работал процесс осциллографирования, который в реальном времени перегонял данные из кольцевого буфера во FRAM, во FLASH формируя осциллограммы в определённом формате, осуществляя синхронизацию, передискретизацию потока и многое другое. Вот именно его и реализовал вышеописанным способом.
Реализовать в виде задачи ОС это было неоптимально, из-за требований к скорости работы и других требований.
Этот процесс даже описанный указанным способом занимает около 24кБ в исходнике, а в виде классического switch/case - страшно даже подумать. И нереально отладить.
Выкладывать сюда эту реализацию не буду, так как во-первых - коммерческий проект; во-вторых - исходник этот - почти сотня КБ - смысла нет, всё равно никто не станет разбираться в таком объёме, если даже сможет wink.gif

Так же использовал такой метод при опросе через nRF24L01+ через короткие окна (неск. мсек) удалённого устройства, где тоже весь протокол обмена был описан в виде многоуровневого автомата, и протокол довольно объёмный, так что в виде классического автомата реализовывать - слишком громоздко, а в виде задачи ОС - по требованиям скорости не проходило, так как было нужно много мелких переключений задач.
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Feb 2 2017, 15:50
Сообщение #39


Гуру
******

Группа: Свой
Сообщений: 2 659
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(jcxz @ Feb 2 2017, 19:07) *
занимает около 24кБ в исходнике, а в виде классического switch/case - страшно даже подумать.

Оптимизацию включать пробовали? wink.gif Еще лет 10 назад тот ИАР для того же AVR при оптимизации заменял switch-case на массив функций.

Теперь сравниваем вызов функции по индексу, который используется автором, с Вашей системой.
Выход из функции и вызов ее опять (или вызов следующей при смене состояния) = восстановить регистры, а затем их сохранить.
Ваш вариант = сохранить регистры, а потом восстановить их опять.

Разница - да, она есть, и заключается вот в чем - в одном случае человек в поезде лицом в направлении движения, а в другом - спиной в направлении движения. А поезд тот же, и везет точно так же. Нету разницы!

Экономии программной памяти в огромном количестве - нет! Увеличения быстродействия - нет! (потому что восстановление/сохранение контекста не оптимизировано). Может вызов функции по индексу и требует пары лишних байт, зато позволяет легко организовать иерархию автоматов.


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
demiurg1978
сообщение Feb 2 2017, 16:33
Сообщение #40


Местный
***

Группа: Участник
Сообщений: 320
Регистрация: 19-12-13
Из: Новосибирск
Пользователь №: 79 709



Что-то мне это баловство со стеком не нравится. Хорошо, сохранили контекст. Убежали в другой обработчик. А тут бац. Ситуация в корне поменялась. И тут мы прибегаем в обработчик, где в сохраненных регистрах старые данные. Да такая система, что обезьяна с гранатой. Никогда не знаешь, что произойдет и куда прилетит...
Go to the top of the page
 
+Quote Post
jcxz
сообщение Feb 3 2017, 09:35
Сообщение #41


Гуру
******

Группа: Свой
Сообщений: 3 292
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(demiurg1978 @ Feb 2 2017, 18:33) *
И тут мы прибегаем в обработчик, где в сохраненных регистрах старые данные. Да такая система, что обезьяна с гранатой. Никогда не знаешь, что произойдет и куда прилетит...

Какие старые данные в каких регистрах???
Вы что такое "переключение контекста" понимаете? Как например это используется в ОС понимаете?
Советую подучить теорию.

Цитата(Dog Pawlowa @ Feb 2 2017, 17:50) *
Оптимизацию включать пробовали? wink.gif Еще лет 10 назад тот ИАР для того же AVR при оптимизации заменял switch-case на массив функций.

А Вы читать, то что я написал - пробовали? Что такое "исходник" понимаете?
Я вообще ничего не говорил о скомпилённом размере. Я говорил о сложности "объёмного исходного кода", который для классического автомата будет ещё большего размера и очень запутанным.

И не знаю где там IAR заменяет что-то на массив функций, я по коду IAR для ARM вижу, что на месте switch() такого автомата IAR генерит огромную последовательность из
десятков пар инструкций CMP/BEQ. Вне зависимости - включена оптимизация или нет.
Так что даже по скорости вариант с переключением контекста будет быстрее.

Цитата(Dog Pawlowa @ Feb 2 2017, 17:50) *
Разница - да, она есть, и заключается вот в чем - в одном случае человек в поезде лицом в направлении движения, а в другом - спиной в направлении движения. А поезд тот же, и везет точно так же. Нету разницы!

Следуя Вашей аналогии: в Вашем случае человек добирается до цели кучей разных поездов, перепрыгивая из одного в другой; в моём - едет на одном поезде и какая разница как он там сидит - спиной или лицом - главное то, что ему удобно и он может в это время полезными делами заниматься, а не прыганьем из одного поезда в другой. laughing.gif

Цитата(Dog Pawlowa @ Feb 2 2017, 17:50) *
Экономии программной памяти в огромном количестве - нет! Увеличения быстродействия - нет! (потому что восстановление/сохранение контекста не оптимизировано). Может вызов функции по индексу и требует пары лишних байт, зато позволяет легко организовать иерархию автоматов.

Ещё раз - попробуйте прочитать хотя-бы мои сообщения, на которые Вы пытаетесь отвечать!
Цель не стояла - увеличение быстродействия или тем более - экономия пары байт программной памяти (что вообще полный бред в современных условиях).
Цель: кардинальное улучшение читаемости и соответственно - удобства написания/отладки кода больших сложных автоматов.
Но даже если заниматься ерундой и экономить байты памяти программ:
Попробуйте когда-нить открыть листинг скомпилённой программы. Увидите, что вызов/возврат из функции занимает далеко не пару байт, даже думаю на AVR.
Каждая такая функция это: её вызов (косвенный, который дороже прямого вызова + адресация в массиве указателей) + сохранение регистров на входе в неё + восстановление регистров на выходе + возврат. Сколько это байт будет на AVR?
В моём случае в таком месте будет только: прямой вызов функции. Всё! Сколько это байт будет на AVR?
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Feb 3 2017, 11:24
Сообщение #42


Гуру
******

Группа: Свой
Сообщений: 2 659
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(jcxz @ Feb 3 2017, 12:35) *
Цель: кардинальное улучшение читаемости и соответственно - удобства написания/отладки кода больших сложных автоматов.

Банальный макрос #define SwitchStack(N) } void Step##N##() {
делает то же самое "улучшение" читаемости и удобство. Все равно место вызова Вашей функции не берется с потолка.


Цитата(jcxz @ Feb 3 2017, 12:35) *
Но даже если заниматься ерундой и экономить байты памяти программ:
...Каждая такая функция это: её вызов (косвенный, который дороже прямого вызова + адресация в массиве указателей) + сохранение регистров на входе в неё + восстановление регистров на выходе + возврат. Сколько это байт будет на AVR?

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

Еще что-то есть? wink.gif


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
Obam
сообщение Feb 3 2017, 11:46
Сообщение #43


Знающий
****

Группа: Участник
Сообщений: 546
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата
Ваш вызов функции против моего вызова функции. Ваше переключение контекста гарантированно дольше


Простите, что вставляю свои 5 коп, но приводя исходники и рассказывая идею, jcxz чётко заявлял об ARM: а в нём конвейерная организации. В AVR тоже есть конвейер? Контекст сохраняется одинаково?
Так что, речь может идти только о удобочитаемости исходников.

И что останавливает от проверки одного и того же кода для ARM и AVR. Кстати, нужен только симулятор (а они есть и недурные, хоть в том же IAR) ядер.

Сообщение отредактировал Obam - Feb 3 2017, 11:47


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Feb 3 2017, 13:46
Сообщение #44


Гуру
******

Группа: Свой
Сообщений: 3 292
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Dog Pawlowa @ Feb 3 2017, 13:24) *
Банальный макрос #define SwitchStack(N) } void Step##N##() {
делает то же самое "улучшение" читаемости и удобство. Все равно место вызова Вашей функции не берется с потолка.

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

Цитата(Dog Pawlowa @ Feb 3 2017, 13:24) *
Немало, тут я полностью согласен. Но вызов функции по индексу - это один раз на всю программу, преамбула/постамбула тоже одни на всех.

Это почему это сохранение/восстановление контекста одно на всех? Разве в соглашениях вызова функций для AVR сохранение контекста делает вызывающий функцию,
а не сама функция? В любом случае - разница даже в десятки байт - ни о чём, смысла нет обсуждать.

Цитата(Dog Pawlowa @ Feb 3 2017, 13:24) *
Ваше переключение контекста гарантированно дольше, так как должно покрыть все используемые всей функцией регистры, мое переключение (вызов-возврат) в среднем короче, потому что адаптировано к конкретному куску кода, выделенному в отдельную функцию.

Да ладно?! А переменные, которые Ваши состояния автомата используют их нет? Без переменных? В моём случае - они хранятся в регистрах и сохраняются/восстанавливаются одним и тем же кодом, а у Вас - для каждого состояния придётся их на входе в каждое состояние заново читать, а после - записывать.
Если уж Вас так волнует количество байт кода, то как раз мой вариант в любом случае будет короче.
Попробуйте на практике реализовать для автомата хотя бы с десятком состояний.

Цитата(Dog Pawlowa @ Feb 3 2017, 13:24) *
Еще что-то есть? wink.gif

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

Цитата(Obam @ Feb 3 2017, 13:46) *
Так что, речь может идти только о удобочитаемости исходников.

Именно об этом и шла речь в первую очередь.
Но некоторые товарищи погрязли в однобайтном мирке, похоже никогда не видели исходников размером хотя-бы несколько сотен строк и похоже объяснять что-то бесполезно....
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Feb 4 2017, 10:28
Сообщение #45


Гуру
******

Группа: Свой
Сообщений: 2 659
Регистрация: 14-07-06
Пользователь №: 18 823



>> Покажите как Вы с помощью этого макроса реализуете условное изменение состояния автомата? А цикл?
А как Вы со своей функцией реализуете условное изменение состояния автомата? - Никак. Вы хотели линейности кода - вот оно.

>> Ну да, а изменение значения переменной-состояния автомата где?
>> А если эта переменная меняется условно, в зависимости от результата выполнения предыдущего состояния автомата?
Так еще проще, чем у Вас - присвоил новое значение и вышел. Естественное структурирование автомата. А у Вас - if (..) goto ?

>>В N-й раз уже говорю, но похоже не доходит sad.gif( - Мой метод оптимален для сложных автоматов,
Вы в автоподпись добавьте - крут, как яйца wink.gif

>> с большим числом состояний
"Большим" - это сколько? У меня сотни - без проблем.

>> условными переходами между состояниями, циклическим выполнением каких-то шагов автомата
1. Бывают автоматы без условных переходов и циклического выполнения?
2. Вот не знал, что есть проблемы реализовать переходы (условные и безусловные) и циклы с массивами функций.

>>общих последовательностей шагов (которые моим методом оформляются в простые функции).
Вы наверное и сами функции изобрели? wink.gif
Общие последовательности шагов реализуются добавлением одной переменной, которая указывает куда выйти после окончания последовательности, она есть и в Вашей реализации.

>> Это почему это сохранение/восстановление контекста одно на всех? Разве в соглашениях вызова функций для AVR сохранение контекста делает вызывающий функцию,
>>а не сама функция? В любом случае - разница даже в десятки байт - ни о чём, смысла нет обсуждать.
Да, тут я погорячился, восстановление контекста одно на всех, а вот сохранение конечно раздельное.

>> А переменные, которые Ваши состояния автомата используют их нет? Без переменных? В моём случае - они хранятся в регистрах и сохраняются/восстанавливаются одним и тем же кодом,
>> а у Вас - для каждого состояния придётся их на входе в каждое состояние заново читать, а после - записывать.
А у Вас этой записи нет?! А в стек и обратно Вы переменные не гоняете? wink.gif Мои переменные лежат там спокойно и работа с ними идет, когда нужно, а Вы туда-сюда, туда-сюда.
Я же написал уже, что у меня запись и восстановление оптимизированы по месту, а у Вас всегда пишутся и читаются все регистры, которые задействованы во всей функции поддержки автомата.
А Вы не поняли и недостаток пытаетесь выдать за достоинство.

>> Если уж Вас так волнует количество байт кода, то как раз мой вариант в любом случае будет короче.
>> Попробуйте на практике реализовать для автомата хотя бы с десятком состояний.
Это называется "на слабо" sm.gif Да, наверное есть случаи, когда Ваш метод имеет смысл. Спасибо, я попробую.


>>Всё уже было. Если Вы не поняли - очевидно рано ещё, со временем может поймёте.
>>Но некоторые товарищи погрязли в однобайтном мирке, похоже никогда не видели исходников размером хотя-бы несколько сотен строк и похоже объяснять что-то бесполезно....
Спасибо, что снизошли!


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 25th May 2017 - 23:53
Рейтинг@Mail.ru


Страница сгенерированна за 0.01511 секунд с 7
ELECTRONIX ©2004-2016