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

 
 
> Таблица переходов вместо Switch, Keil Си
AndreyS
сообщение Mar 23 2010, 15:28
Сообщение #1


Местный
***

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



Добрый день.

Если я не первый раз поднимаю эту тему, то заранее извиняюсь (я не смог придумать поисковику удобоваримое слово для поиска. На void* или таблица вываливается куча страниц).

Хочу заменить конструкцию Switch case на таблицу переходов и все это на языке Си.

Как вызвать процедуру по адресу я знаю, вопрос как бы мне заполнить таблицу с 256 значениями.
На асме я это реализовывал так:
Сначала создавал массив адресов на обработчик default, а затем в другом инклюднике прописывал (переопределял по вычисленным адресам определенные обработчики) Вот так:
Код
COM_SN_WRITE     EQU    42h                    ; Команда записи SN
    ORG TABEL_COM+(COM_SN_WRITE*2)              ; тут умножаю на 2, так как храню адрес из 2-х байт, в Keil Си он 3-х байтовый
    DW SEND_COM_SN_WRITE                               ; Ну а тут собственно сам обработчик (процедура). Тут ее адрес


SEND_COM_SN_WRITE:
       RET


TABEL_COM это адрес таблицы
COM_SN_WRITE номер команды
SEND_COM_SN_WRITE адрес обработчика

Как бы мне теперь так же сделать на Си в Keil?

PS Работу switch в Keil я разобрал, он работает с таблицей не так как мне нужно (она все равно перебором просматривает всю свою таблицу).


--------------------
Удачи.
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 35)
aaarrr
сообщение Mar 23 2010, 15:43
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Определите массив указателей на функции, например, массив из 10 указателей на функции вида int func(int, int) будет выглядеть так:
Код
int (*zzz[10])(int, int);
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 23 2010, 16:30
Сообщение #3


Гуру
******

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



Код
typedef void (*VECTORS)();

const VECTORS function[stQty] =
{
  f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,  f8,  f9,
  f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
  f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
  f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
  f40, f41, f42, f43, f44, f45, f46, f47, f48, f49,
  f50, f51, f52, f53, f54, f55, f56, f57, f58, f59,
  f60, f61, f62, f63, f64, f65, f66, f67, f68, f69,
  f70, f71, f72, f73, f74, f75, f76, f77, f78, f79,
  f80, f81, f82, f83, f84, f85, f86, f87, f88, f89,
  f90, f91, f92, f93, f94, f95, f96, f97, f98, f99,
  f100,f101,f102,f103
   };


Цитата(AndreyS @ Mar 23 2010, 19:28) *
...PS Работу switch в Keil я разобрал, он работает с таблицей не так как мне нужно (она все равно перебором просматривает всю свою таблицу).

Оптимизация включена?


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
baralgin
сообщение Mar 23 2010, 17:08
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680



Цитата(Dog Pawlowa @ Mar 23 2010, 18:30) *
Оптимизация включена?

По идее компилятор такой самодеятельностью заниматься не должен. Ведь для этого понадобится дополнительная статическая память. А так конечно, нужно разобраться что такое указатели на функции, и дальше наиболее оптимальные решения будут сами проситься.
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 23 2010, 17:45
Сообщение #5


Гуру
******

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



Цитата(baralgin @ Mar 23 2010, 20:08) *
По идее компилятор ....
Ведь для этого понадобится дополнительная статическая память.

ИАР, к примеру, занимается.
Зачем статическая память? Все можно сделать в программной памяти.


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
zltigo
сообщение Mar 23 2010, 17:58
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(baralgin @ Mar 23 2010, 20:08) *
По идее компилятор такой самодеятельностью заниматься не должен.

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
AndreyS
сообщение Mar 23 2010, 19:10
Сообщение #7


Местный
***

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



Цитата(Dog Pawlowa @ Mar 23 2010, 19:30) *
[code]typedef void (*VECTORS)();

const VECTORS function[stQty]={указатели}

Оптимизация включена?

спасибо большое за ответ. Меня интересовало как в таблицу, в произвольном порядке прописать адрес функции. Вот например таблица изначально заполнена адресом на один обработчик заглушку. Теперь я создал например обработчик 10-го позиционного номера таблицы. И хочу что бы компилятор в таблице заменил адрес 10 ячейки этой таблицы. На асме я это регулировал оргом, тут с _at_ такая штука не проходит. а нужно мне это для дополнения обработчиков. Ну всего 256 комбинаций (у меня байт проверяется), из них 200 определено. И вот хочу еще 2 определить, что бы не искать позицию в таблице, я хотел что бы компилятор (по моему указанию) высчитал позицию адреса в таблице и туда этот адрес положил. А как вызвать функию по адресу из этой таблицы я знаю, спасибо.

Цитата(Dog Pawlowa @ Mar 23 2010, 19:30) *
Оптимизация включена?

оптимхизация включена (какой уровень сейчас не скажу да это и не важно). У кейла в факе на сайте по этому поводу сказано что начиная 7 версии свитчь сам сворачивается в таблицу в зависимости отусловий (от кода). Я стал анализировать. Он таблицу создает сразу от 6 кейсов, если кейсы стоят последовательно (т.е. Сравниваемое значение в каждом кейсе отличается от предыдущего на 1). Если их перетасовать, то таблица появляетя уже если кейсов более 10. Но это все фигня. Я зашел в их функию ccall за которой в коде лежит таблица, и посмотрел что она делает. Оказалось что 3-х байтовая таблица это не просто адрес. А 2 байта адрес и значение кейса. И фукция производит в цикле поиск значенния первого байта адреса равного 0. Это означает для нее что вся таблица перебрана и совпадения нет. И тут находится адрес обработчика дефаулт значения. Если первый байт в таблице не равен 0, то тогда сравнивается 3-й байт в таблице (в нем лежит кейс значение). Если он совпал с входящим числом (switch), то выполняется переход на адрес (1 и 2 ячейки таблицы). Иначе ищет дальше. Нахрена такая таблица я не понял. Компактно - да, быстро - нет.


--------------------
Удачи.
Go to the top of the page
 
+Quote Post
baralgin
сообщение Mar 23 2010, 19:18
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680



Dog Pawlowa, zltigo, Спасибо, буду знать, а то больших свитчей как-то побаивался.

AndreyS, Что-то не совсем понятно. У вас есть две сотни обработчиков? Изменить в таблице(массив указателей) адрес функции не сложно. Хотя если вы уже инициализировали этот массив, то в чём вообще проблема?
mas_func[10] = &new_handler;
// где new_handler ваша функция(естественно такого же типа как и элементы массива).
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 23 2010, 19:25
Сообщение #9


Гуру
******

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



Цитата(AndreyS @ Mar 23 2010, 22:51) *
Меня интересовало как в таблицу, в произвольном порядке прописать адрес функции.

Ну пишете в произвольком порядке и все, вот как я: wink.gif

Код
/ basic functions:
STATE ( Restart            ,    "Restart"          ,  "Neustart"         ,    0        )
STATE ( SelfTest           ,    "Self-test"        ,  "Selbsttest"       , CLR+STN    )
STATE ( Waiting            ,    "Ready"            ,  "Bereit"           ,    0        )
STATE ( AirDeleting        ,    "Air out "         ,  "Entl"uuml"ften"   , CLR+STN    )


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

Цитата(baralgin @ Mar 23 2010, 23:18) *
Изменить в таблице(массив указателей) адрес функции не сложно. ..
mas_func[10] = &new_handler;

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


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Mar 23 2010, 19:38
Сообщение #10


фанат дивана
******

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



Цитата(AndreyS @ Mar 24 2010, 00:10) *
Меня интересовало как в таблицу, в произвольном порядке прописать адрес функции. Вот например таблица изначально заполнена адресом на один обработчик заглушку. Теперь я создал например обработчик 10-го позиционного номера таблицы. И хочу что бы компилятор в таблице заменил адрес 10 ячейки этой таблицы.


Таким макаром сделаны обработчики прерываний для Cortex-M3 STM32. Для gcc это делается так:
Код
// объявления всех нужных обработчиков
#define WEAK __attribute__ ((weak))
void WEAK f00(void);
void WEAK f01(void);
...
void WEAK f255(void);

//таблица :
void (* const Handlers[])(void) =
{
    f00,
    f01,
...
    f255
}

// и заглушки по умолчанию:
#pragma weak f00 = Default_Handler
#pragma weak f01 = Default_Handler
...
#pragma weak f255 = Default_Handler


Теперь для объявления своего обработчика №25 просто пишем в любом c-файле
Код
void f25()
{
    //
}

и эта функция попадает в нужное место.

Но в кейле для этого приходится залезать в ассемблерsmile.gif

Код
        MACRO
        def_int_vector  $HandlerName
$HandlerName  PROC
              EXPORT  $HandlerName  [WEAK]
              B  .
              ENDP
        MEND


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
AndreyS
сообщение Mar 23 2010, 19:59
Сообщение #11


Местный
***

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



Цитата(Dog Pawlowa @ Mar 23 2010, 22:25) *
Ну пишете в произвольком порядке и все, вот как я: wink.gif

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

Я понял, что задача автора сделать удобной инициализацию массива. Или?

ууу. С вашим кодом я поплыл, что такое state я не знаю :-(

я был не полностью откровенен. Keil в данном случае 51 ядро, массив конечно лежит в областе code.

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

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

Цитата(AHTOXA @ Mar 23 2010, 22:38) *
Таким макаром сделаны обработчики прерываний для Cortex-M3 STM32. Для gcc это делается так:
Код
код проглотил

и эта функция попадает в нужное место.


во. Это то что мне нужно. Попробую покрутить в keilе 51.


--------------------
Удачи.
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 23 2010, 20:07
Сообщение #12


Гуру
******

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



Цитата(AndreyS @ Mar 23 2010, 23:59) *
С вашим кодом я поплыл, что такое state я не знаю :-(

Это просто мой макрос, определение которого меняется в программе несколько раз.
Не "грязный хак", но любители строгого С обычно стоят в сторонке. smile.gif


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
AndreyS
сообщение Mar 23 2010, 20:41
Сообщение #13


Местный
***

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



Цитата(Dog Pawlowa @ Mar 23 2010, 23:07) *
Это просто мой макрос, определение которого меняется в программе несколько раз.
Не "грязный хак", но любители строгого С обычно стоят в сторонке. smile.gif


ага. Значит читать мне надо про макросы?

Цитата(AHTOXA @ Mar 23 2010, 22:38) *
Таким макаром сделаны обработчики прерываний для Cortex-M3 STM32. Для gcc это делается так:
...
и эта функция попадает в нужное место.

а как бы к этому математику подтянут?. Пример. Имеем команду ENTER, она имеет числовое значение равное 10. Получается что ее обработчик f10. А теперь положим сменилось ее числовое значение на другое. Получается нужно не забыть переименовать обработчик.
Как бы привязать заполнение таблицы к номеру команды? И исходя из ее значения в соответствующую ячейку таблицы попадал адрес обработчика. Сменил я номер команды и адрес автоммтом лег в новую ячейку, а в старую опять вернулся адрес дефаулт обработчика.

Сообщение отредактировал rezident - Mar 24 2010, 01:39
Причина редактирования: Нарушение п.3.4 Правил форума.


--------------------
Удачи.
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 23 2010, 20:55
Сообщение #14


Гуру
******

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



Цитата(AndreyS @ Mar 24 2010, 00:14) *
ага. Значит читать мне надо про макросы?

Желательно, только сразу не лезьте в дебри.
Альтернатива предложению от АНТОХА:
В простейшем виде пишете
#define f25 /*empty_function*/my_function_for_code_25

Но Вы оперируете конкретными индексами, в данном случае 25.
Это неудобно, но непонятно где привязка к конкретным номерам.
Если только в Вашей программе, то нее нужно избавляться, как это сделано у меня.
Но если индекс участвует в обмене с другим прибором, и языки программирования разные, то красиво трудно сделать.


Цитата(AndreyS @ Mar 24 2010, 00:41) *
Как бы привязать заполнение таблицы к номеру команды?

Ладно, покажу, как это делается у меня, может другие более простой способ подскажут.

Код
enum {
#define STATE( name, engl, germ, prop) st##name,
#include STATES_HEADER
#undef STATE
stQty
};


const VECTORS function[stQty] = {
#define STATE( name, engl, germ, prop) f##name ,
#include STATES_HEADER
#undef STATE
};


Сообщение отредактировал rezident - Mar 24 2010, 01:40
Причина редактирования: Оформление цитаты исходника.


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Mar 23 2010, 21:54
Сообщение #15


фанат дивана
******

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



Цитата(AndreyS @ Mar 24 2010, 01:41) *
а как бы к этому математику подтянут?. Пример. Имеем команду ENTER, она имеет числовое значение равное 10. Получается что ее обработчик f10. А теперь положим сменилось ее числовое значение на другое. Получается нужно не забыть переименовать обработчик.
Как бы привязать заполнение таблицы к номеру команды?


Ну это уже мелочиsmile.gif

Код
#define DECLARE_COMMAND_HANDLER2(cmd_number) void f##cmd_number(void)
#define DECLARE_COMMAND_HANDLER(cmd_number) DECLARE_COMMAND_HANDLER2(cmd_number)

#define CMD_ENTER  10

DECLARE_COMMAND_HANDLER(CMD_ENTER)
{
  for (;;);
}


Код
DECLARE_COMMAND_HANDLER(CMD_ENTER)

развернётся в
Код
void f10(void)


При смене CMD_ENTER на 20 - станет
Код
void f20(void)
.


Цитата(Dog Pawlowa @ Mar 24 2010, 01:55) *
В простейшем виде пишете
#define f25 /*empty_function*/my_function_for_code_25


Это отличный вариант, пока все обработчики хранятся в одном файле. Но иногда (часто) нужно, чтоб модуль при подключении автоматически добавлял свой элемент в таблицу. В случае фиксированной таблицы (с известным заранее числом элементов, типа таблицы векторов прерываний) - можно применить вариант, который я привёл. А вот для произвольной таблицы - я так ничего путного и не придумал.
А как было бы здорово, если бы модуль (.c файл) мог при его добавлении в проект, скажем, автоматически добавить несколько своих терминальных команд, пару переменных в конфиг, етцsmile.gif
Придумалось только для плюсов, через смесь шаблонов и макросов. Да и то не всё там гладко, накладные расходы по ОЗУ (не всё во флеше), и работоспособность зависит от порядка вызова глобальных конструкторов (не определён стандартом, емнимс).


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 23 2010, 22:02
Сообщение #16


Гуру
******

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



Цитата(AHTOXA @ Mar 24 2010, 01:54) *
Это отличный вариант, пока все обработчики хранятся в одном файле.

Ну почему, они отлично подключаются через заголовочные файлы.
Но автоматически не добавляются, ага.
Может это и хорошо? wink.gif


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
sonycman
сообщение Mar 27 2010, 05:48
Сообщение #17


Любитель
*****

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



Цитата(AndreyS @ Mar 23 2010, 23:10) *
оптимхизация включена (какой уровень сейчас не скажу да это и не важно).
...
Нахрена такая таблица я не понял. Компактно - да, быстро - нет.

Как это не важно?
У Вас какой режим оптимизации включен, по размеру или по времени?
А если по размеру? Вот он вам такой код и генерит.
Поставте О3, и включите опцию оптимизации по времени.
Возможно, и не понадобится вся эта канитель, что тут развели smile.gif
Go to the top of the page
 
+Quote Post
AndreyS
сообщение Mar 29 2010, 08:32
Сообщение #18


Местный
***

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



Цитата(sonycman @ Mar 27 2010, 09:48) *
Как это не важно?
У Вас какой режим оптимизации включен, по размеру или по времени?
А если по размеру? Вот он вам такой код и генерит.
Поставте О3, и включите опцию оптимизации по времени.
Возможно, и не понадобится вся эта канитель, что тут развели smile.gif



Добрый день.

Тип оптимизации по времени с повторным использованием одинакового куска кода (сворачиват повторения в процедуры).

А канитель эта по любому нужна wink.gif


--------------------
Удачи.
Go to the top of the page
 
+Quote Post
defunct
сообщение Apr 4 2010, 23:56
Сообщение #19


кекс
******

Группа: Свой
Сообщений: 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
};

И вручную следить за чистотой этого массива. Найти место для пары новых обработчиков когда все в чистоте не составит никакой сложности. Да и обратная операция - читать этот массив человеку который будет поддерживать код после вас будет легко, - ему не придется бегать к каждой функции и смотреть в какую позицию она загружена.
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Apr 5 2010, 10:24
Сообщение #20


Гуру
******

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



Цитата(defunct @ Apr 5 2010, 02:56) *
А что мешает просто красиво задать массив, - с одной функцией в одной строке и коментарием в конце строки, который будет указывать номер текущей позиции:
...И вручную следить за чистотой этого массива.

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


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
RobFPGA
сообщение Apr 5 2010, 20:36
Сообщение #21


Профессионал
*****

Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643



Приветствую!


Цитата(AHTOXA @ Mar 24 2010, 00:54) *
Это отличный вариант, пока все обработчики хранятся в одном файле. Но иногда (часто) нужно, чтоб модуль при подключении автоматически добавлял свой элемент в таблицу. В случае фиксированной таблицы (с известным заранее числом элементов, типа таблицы векторов прерываний) - можно применить вариант, который я привёл. А вот для произвольной таблицы - я так ничего путного и не придумал.
А как было бы здорово, если бы модуль (.c файл) мог при его добавлении в проект, скажем, автоматически добавить несколько своих терминальных команд, пару переменных в конфиг, етцsmile.gif
Придумалось только для плюсов, через смесь шаблонов и макросов. Да и то не всё там гладко, накладные расходы по ОЗУ (не всё во флеше), и работоспособность зависит от порядка вызова глобальных конструкторов (не определён стандартом, емнимс).


Я похожее делал для определения набора переменных в flash. Структуры задающие переменные (в разных модулях) при определении назначались в именованный сегмент памяти. При линковке все что в этом сегменте было определено складывалось в одну большую таблицу начало и размер которой известны. Естественно положить таким образом указатель в определенную позицию в таблице нельзя.

Успехов! Rob/
Go to the top of the page
 
+Quote Post
defunct
сообщение Apr 6 2010, 01:40
Сообщение #22


кекс
******

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



Цитата(Dog Pawlowa @ Apr 5 2010, 13:24) *
Я делал так раньше, неудобно - слишком много переименовывать.
Как раз на днях заказчик попросил поменять последовательность функций в менюшке. Одно дело перетасовать имена функций, другое дело отслеживать физические индексы. Не говоря уже о том, чтобы добавить раздел в меню.

Если смотреть в контексте использования для какого-то протокола из-вне (модбас / мэк101 / 104 и т.п. много всяких у кого 256 функций), где функции (большинство их) жестко определены стандартом. То существенно менять ничего не придется, никто функции протокола менять не будет. Функции могут только неспешно добавляться как и отметил автор ветки.

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

вместо таблицы голых функций.
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 6 2010, 03:05
Сообщение #23


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(), поэтому
// ссылку можно безопасно использовать

Есть небольшие накладняки на создание статического объекта, но они небольшие - соизмеримы с вызовом конструктора. Работает этот прием очень хорошо.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Apr 6 2010, 07:02
Сообщение #24


Гуру
******

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



Цитата(defunct @ Apr 6 2010, 04:40) *
А для меню думаю куда удобнее и нагляднее ...

А я не исключаю включение в массив дополнительно к указателям на функции вспомогательной информации. Но для меня реализация всего интерфейса пользователя как единого автомата состояний получается гораздо прозрачнее и удобнее. Законченный фрагмент исходника должен поместиться на экране. Меньше ссылок, больше прямых действий. От "глобальной" индесации массива функций [state][event] я сделал шаг назад, к function[state].
Впрочем, я уже о своем, наболевшем - не перебдеть в структурировании smile.gif


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 6 2010, 07:45
Сообщение #25


фанат дивана
******

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



Цитата(dxp @ Apr 6 2010, 09:05) *
Код
// при создании ссылки внутри singleton<TSlon> будет
// статически создан и проинициализирован объект внутри Instance(), поэтому
// ссылку можно безопасно использовать


А чем нам поможет замена глобального объекта на глобальный статический? В плане руления порядком вызова конструкторов? То есть, чем это отличается от простого объявления
Код
TSlon slon;
?
Имхо, без динамического создания объектов singleton совершенно бесполезен.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 6 2010, 11:14
Сообщение #26


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(). И живет там все время, пока программа работает. Т.е. по сути как обынчый глобальный объект, но спрятанный внутри функции и предоставляющий доступ по ссылке (что синтаксически ровно как доступ к обычному объекту). Нету тут ни работы с кучей, ни выделения памяти на рантайме. Выделение памяти и инициализация производятся комилятором на основе правил языка в части статических объектов внутри функций (которые есть даже в голом С).


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 6 2010, 12:15
Сообщение #27


фанат дивана
******

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



Цитата(dxp @ Apr 6 2010, 17:14) *
Вот зрасьте! В этом же вся фишка синглтона.


Упс. Я был уверен, что разница между статическим и глобальным объектом только в области видимости.
А ты хочешь сказать, что для статических объектов конструкторы вызываются не в списке глобальных конструкторов, а при первом вызове функции, в которой он содержится? Если так, то это супер! Надо проверитьsmile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 6 2010, 12:56
Сообщение #28


Adept
******

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



Цитата(AHTOXA @ Apr 6 2010, 19:15) *
А ты хочешь сказать, что для статических объектов конструкторы вызываются не в списке глобальных конструкторов, а при первом вызове функции, в которой он содержится? Если так, то это супер! Надо проверитьsmile.gif

Статический объект должен быть гарантировано проинициализирован до его использования. А где это делается - отдано на откуп реализации. Например:
Код
void f()
{
    int a = 10;
    ... // код функции
}

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 6 2010, 17:57
Сообщение #29


фанат дивана
******

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



Цитата(dxp @ Apr 6 2010, 18:56) *
Главное, что поведение четко стандартизовано и это можно безопасно использовать.


Попробовал, получилось. Но далеко не сразу. Простая замена глобального объекта
Код
uart1_t uart1;

на ссылку:
Код
uart1_t& uart1 = singleton<uart1_t>::Instance();

Не прокатила. Потому что теперь вместо глобального объекта uart1 у нас получилась глобальная же ссылкаsmile.gif Порядок инициализации которой (на этот раз при помощи хитрого синглетона!) по прежнему не определён.
Пришлось везде, где используется uart1, заводить локальные переменные-ссылки
Код
uart1_t& localuart = singleton<uart1_t>::Instance();

и использовать их. Вот тогда всё заработало должным образомsmile.gif
Что касаемо накладных расходов, то они достаточно приличные:
Код
*с глобальным 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? smile.gif )


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 7 2010, 03:51
Сообщение #30


Adept
******

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



Цитата(AHTOXA @ Apr 7 2010, 01:12) *
Пришлось везде, где используется uart1, заводить локальные переменные-ссылки
Код
uart1_t& localuart = singleton<uart1_t>::Instance();

и использовать их. Вот тогда всё заработало должным образомsmile.gif

Конечно, именно так и надо делать, в этом и смысл. Точнее, глобальную ссылку завести тоже не лишне, но ее использовать по ходу программы, а вот в конструкторах - да, только локальные ссылки.

Цитата(AHTOXA @ Apr 7 2010, 01:12) *
Я думаю, что для некоторых применений это хорошее решение, по крайней мере я намерен его применять.
(Или всё же new? smile.gif )

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 7 2010, 04:07
Сообщение #31


фанат дивана
******

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



Цитата(dxp @ Apr 7 2010, 10:06) *
Для new надо свой быстрый и не подверженный фрагментации менеджер памяти сделать. Если только для вышеописанных целей, то это будет еще больше накладных. А вообще такой мененжер памяти местами очень полезен.


Если new будет использоваться только как замена глобальным объектам, то фрагментация ему не грозит, ибо будет только new, без delete. Но если
Цитата
Надо будет сделать, как руки дойдут.

, то я только заsmile.gif
ЗЫ. Пока прикрутил bget, вроде работает.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 7 2010, 06:24
Сообщение #32


Adept
******

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



Цитата(AHTOXA @ Apr 7 2010, 11:22) *
Если new будет использоваться только как замена глобальным объектам, то фрагментация ему не грозит, ибо будет только new, без delete.

А тогда смысла нет в динамическом управлении памятью. Смысл ведь в том, чтобы юзать одну и ту же память под разные цели в разные моменты времени. Как стек, только со временем жизни объектов, определяемым пользователем. А если без delete, то тот вариант во статиками внутри получается функционально почти такой же, а по накладным лучше.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 7 2010, 07:51
Сообщение #33


фанат дивана
******

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



Цитата(dxp @ Apr 7 2010, 12:39) *
А тогда смысла нет в динамическом управлении памятью. Смысл ведь в том, чтобы юзать одну и ту же память под разные цели в разные моменты времени.

Смысл в том, что объекты создаются в нужном мне порядке, я управляю этим.
Насчёт увеличения накладных - это вряд ли. ну разве что при создании объекта. При работе - простейшая проверка на null и возврат.
Естественно, если будут нормальные new/delete, то лучше использовать их.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 7 2010, 13:35
Сообщение #34


Adept
******

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



Цитата(AHTOXA @ Apr 7 2010, 15:06) *
Смысл в том, что объекты создаются в нужном мне порядке, я управляю этим.

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 7 2010, 13:44
Сообщение #35


фанат дивана
******

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



А, это конечно. Просто наличие new позволяет даже без всяких синглетонов делать
Код
if (!uart) uart = new uart_t;

, а в случае глобальных объектов я этого лишён.
Статики (спасибо за идею) позволяют обойти это ограничение.
Консенсус? smile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Apr 8 2010, 03:28
Сообщение #36


Adept
******

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



Цитата(AHTOXA @ Apr 7 2010, 20:59) *
Код
if (!uart) uart = new uart_t;

Да, это удобная штука (а местами незаменимая - сейчас приходится с GUI колупаться, очень не хватает простого, легкого и безопасного менеджера памяти. И для STL'ных вещей оно тоже очень нужно, там, правда, придется аллокаторы переписать). Надо будет поставить приоритетной в очередь факультативных задач.

Цитата(AHTOXA @ Apr 7 2010, 20:59) *
Консенсус? smile.gif

Адназначна. cheers.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 25th July 2025 - 22:02
Рейтинг@Mail.ru


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