|
|
  |
Таблица переходов вместо Switch, Keil Си |
|
|
|
Mar 23 2010, 22:02
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(AHTOXA @ Mar 24 2010, 01:54)  Это отличный вариант, пока все обработчики хранятся в одном файле. Ну почему, они отлично подключаются через заголовочные файлы. Но автоматически не добавляются, ага. Может это и хорошо?
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Mar 27 2010, 05:48
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(AndreyS @ Mar 23 2010, 23:10)  оптимхизация включена (какой уровень сейчас не скажу да это и не важно). ... Нахрена такая таблица я не понял. Компактно - да, быстро - нет. Как это не важно? У Вас какой режим оптимизации включен, по размеру или по времени? А если по размеру? Вот он вам такой код и генерит. Поставте О3, и включите опцию оптимизации по времени. Возможно, и не понадобится вся эта канитель, что тут развели
|
|
|
|
|
Mar 29 2010, 08:32
|

Местный
  
Группа: Участник
Сообщений: 235
Регистрация: 28-01-05
Из: Санкт-Петербург
Пользователь №: 2 276

|
Цитата(sonycman @ Mar 27 2010, 09:48)  Как это не важно? У Вас какой режим оптимизации включен, по размеру или по времени? А если по размеру? Вот он вам такой код и генерит. Поставте О3, и включите опцию оптимизации по времени. Возможно, и не понадобится вся эта канитель, что тут развели  Добрый день. Тип оптимизации по времени с повторным использованием одинакового куска кода (сворачиват повторения в процедуры). А канитель эта по любому нужна
--------------------
Удачи.
|
|
|
|
|
Apr 4 2010, 23:56
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(AndreyS @ Mar 23 2010, 22:10)  Теперь я создал например обработчик 10-го позиционного номера таблицы. И хочу что бы компилятор в таблице заменил адрес 10 ячейки этой таблицы. На асме я это регулировал оргом, тут с _at_ такая штука не проходит. а нужно мне это для дополнения обработчиков. Ну всего 256 комбинаций (у меня байт проверяется), из них 200 определено. И вот хочу еще 2 определить, что бы не искать позицию в таблице, я хотел что бы компилятор (по моему указанию) высчитал позицию адреса в таблице и туда этот адрес положил. А как вызвать функию по адресу из этой таблицы я знаю, спасибо. А что мешает просто красиво задать массив, - с одной функцией в одной строке и коментарием в конце строки, который будет указывать номер текущей позиции: Код void CommonHandler() { }
void GetTimeHander() { ... }
void (*Handlers[])(void) = { CommonHandler, // 0 CommonHandler, // 1 CommonHandler, // 2 CommonHandler, // 3 GetTimeHandler, // 4 CommonHandler, // 5 ... CommonHandler, // 55 CommonHandler, // 56 CommonHandler, // 57 ... CommonHandler, // 254 CommonHandler // 255 }; И вручную следить за чистотой этого массива. Найти место для пары новых обработчиков когда все в чистоте не составит никакой сложности. Да и обратная операция - читать этот массив человеку который будет поддерживать код после вас будет легко, - ему не придется бегать к каждой функции и смотреть в какую позицию она загружена.
|
|
|
|
|
Apr 5 2010, 20:36
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Цитата(AHTOXA @ Mar 24 2010, 00:54)  Это отличный вариант, пока все обработчики хранятся в одном файле. Но иногда (часто) нужно, чтоб модуль при подключении автоматически добавлял свой элемент в таблицу. В случае фиксированной таблицы (с известным заранее числом элементов, типа таблицы векторов прерываний) - можно применить вариант, который я привёл. А вот для произвольной таблицы - я так ничего путного и не придумал. А как было бы здорово, если бы модуль (.c файл) мог при его добавлении в проект, скажем, автоматически добавить несколько своих терминальных команд, пару переменных в конфиг, етц  Придумалось только для плюсов, через смесь шаблонов и макросов. Да и то не всё там гладко, накладные расходы по ОЗУ (не всё во флеше), и работоспособность зависит от порядка вызова глобальных конструкторов (не определён стандартом, емнимс). Я похожее делал для определения набора переменных в flash. Структуры задающие переменные (в разных модулях) при определении назначались в именованный сегмент памяти. При линковке все что в этом сегменте было определено складывалось в одну большую таблицу начало и размер которой известны. Естественно положить таким образом указатель в определенную позицию в таблице нельзя. Успехов! Rob/
|
|
|
|
|
Apr 6 2010, 01:40
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Dog Pawlowa @ Apr 5 2010, 13:24)  Я делал так раньше, неудобно - слишком много переименовывать. Как раз на днях заказчик попросил поменять последовательность функций в менюшке. Одно дело перетасовать имена функций, другое дело отслеживать физические индексы. Не говоря уже о том, чтобы добавить раздел в меню. Если смотреть в контексте использования для какого-то протокола из-вне (модбас / мэк101 / 104 и т.п. много всяких у кого 256 функций), где функции (большинство их) жестко определены стандартом. То существенно менять ничего не придется, никто функции протокола менять не будет. Функции могут только неспешно добавляться как и отметил автор ветки. А для меню думаю куда удобнее и нагляднее хранить описатель пункта меню, который включает что-то типа - ссылку на верхнее меню (parent) - ссылку на субменю (если есть) - имя пункта (то что выводится на экран) - параметры шрифта - ссылку на функцию-аутентификатор (не все же можно выполнять сразу, кое-что может требовать особого подтверждения) - ну и ссылку на действие. (специально поставил последним) вместо таблицы голых функций.
|
|
|
|
|
Apr 6 2010, 03:05
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(AHTOXA @ Mar 24 2010, 04:54)  работоспособность зависит от порядка вызова глобальных конструкторов (не определён стандартом, емнимс). С этим можно побороться с помощью паттерна Singleton. Код //--------------------------------------------------------------------------- template<typename T> class singleton { public: static T& Instance() { static T instance; return instance; } }; //--------------------------------------------------------------------------- Использование: Код class TSlon { ... };
TSlon& slon = singleton<TSlon>::Instance();
// далее идет использование слона (синтаксически как обычный объект): // при создании ссылки внутри singleton<TSlon> будет // статически создан и проинициализирован объект внутри Instance(), поэтому // ссылку можно безопасно использовать Есть небольшие накладняки на создание статического объекта, но они небольшие - соизмеримы с вызовом конструктора. Работает этот прием очень хорошо.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 6 2010, 07:45
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(dxp @ Apr 6 2010, 09:05)  Код // при создании ссылки внутри singleton<TSlon> будет // статически создан и проинициализирован объект внутри Instance(), поэтому // ссылку можно безопасно использовать А чем нам поможет замена глобального объекта на глобальный статический? В плане руления порядком вызова конструкторов? То есть, чем это отличается от простого объявления Код TSlon slon; ? Имхо, без динамического создания объектов singleton совершенно бесполезен.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 6 2010, 11:14
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(AHTOXA @ Apr 6 2010, 14:45)  А чем нам поможет замена глобального объекта на глобальный статический? В плане руления порядком вызова конструкторов? То есть, чем это отличается от простого объявления Вот зрасьте! В этом же вся фишка синглтона. Когда какой-то объект нуждается в объекте TSlon, то он создает (использует) ссылку, возвращаемую функцией Instance() шаблона singleton. А ссылка эта ссылается на статический объект, создаваемый внутри фукнции-члена Instance(). Таким образом, получается следующая схема: при первом вызове Instance() будет создан и проинициализирован статический объект требуемого типа (в нашем примере TSlon), все последующие вызовы будут возвращать ссылку на уже существующий объект. И не важно, кто первый дернул Instance(), думать об этом не надо. В этом и избавление от зависимости от порядка вызова конструкторов. Цитата(AHTOXA @ Apr 6 2010, 14:45)  Код TSlon slon; ? Имхо, без динамического создания объектов singleton совершенно бесполезен. Еще как полезен: объект создается как статический внутри статической же функции-члена Instance(). И живет там все время, пока программа работает. Т.е. по сути как обынчый глобальный объект, но спрятанный внутри функции и предоставляющий доступ по ссылке (что синтаксически ровно как доступ к обычному объекту). Нету тут ни работы с кучей, ни выделения памяти на рантайме. Выделение памяти и инициализация производятся комилятором на основе правил языка в части статических объектов внутри функций (которые есть даже в голом С).
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 6 2010, 12:56
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(AHTOXA @ Apr 6 2010, 19:15)  А ты хочешь сказать, что для статических объектов конструкторы вызываются не в списке глобальных конструкторов, а при первом вызове функции, в которой он содержится? Если так, то это супер! Надо проверить  Статический объект должен быть гарантировано проинициализирован до его использования. А где это делается - отдано на откуп реализации. Например: Код void f() { int a = 10; ... // код функции } Реализация может быть разной. Самое простое - сунуть а в секцию, где помещаются глобальные переменные, и проинициализировать вместе с ними (IAR, помнится, так и делает) - разница тут будет только в области видимости. А можно тут вставить код, проверяющий первый вход в функцию, и вызывать инициализатор (это тот самый оверхед, про который я говорил, и который незначителен по сравнению с вызовом конструктора). Как делается реально в том или ином случае - это в ведении реализации (в случае с вызовом конструктора объекта пользовательского типа скорее всего делается по второму варианту). Главное, что поведение четко стандартизовано и это можно безопасно использовать.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 6 2010, 17:57
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(dxp @ Apr 6 2010, 18:56)  Главное, что поведение четко стандартизовано и это можно безопасно использовать. Попробовал, получилось. Но далеко не сразу. Простая замена глобального объекта Код uart1_t uart1; на ссылку: Код uart1_t& uart1 = singleton<uart1_t>::Instance(); Не прокатила. Потому что теперь вместо глобального объекта uart1 у нас получилась глобальная же ссылка  Порядок инициализации которой (на этот раз при помощи хитрого синглетона!) по прежнему не определён. Пришлось везде, где используется uart1, заводить локальные переменные-ссылки Код uart1_t& localuart = singleton<uart1_t>::Instance(); и использовать их. Вот тогда всё заработало должным образом  Что касаемо накладных расходов, то они достаточно приличные: Код *с глобальным uart: text data bss dec hex filename 4372 8 5792 10172 27bc ./exe/stm32-H103.elf *с singleton<uart1_t>: text data bss dec hex filename 4500 8 5800 10308 2844 ./exe/stm32-H103.elf (Всё это gcc на stm32) Я думаю, что для некоторых применений это хорошее решение, по крайней мере я намерен его применять. (Или всё же new?  )
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 7 2010, 03:51
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(AHTOXA @ Apr 7 2010, 01:12)  Пришлось везде, где используется uart1, заводить локальные переменные-ссылки Код uart1_t& localuart = singleton<uart1_t>::Instance(); и использовать их. Вот тогда всё заработало должным образом  Конечно, именно так и надо делать, в этом и смысл. Точнее, глобальную ссылку завести тоже не лишне, но ее использовать по ходу программы, а вот в конструкторах - да, только локальные ссылки. Цитата(AHTOXA @ Apr 7 2010, 01:12)  Я думаю, что для некоторых применений это хорошее решение, по крайней мере я намерен его применять. (Или всё же new?  ) Для new надо свой быстрый и не подверженный фрагментации менеджер памяти сделать. Если только для вышеописанных целей, то это будет еще больше накладных. А вообще такой мененжер памяти местами очень полезен. Надо будет сделать, как руки дойдут.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|