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

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Таблица переходов вместо 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
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

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

 


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


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