Jump to content

    

Инкрементирующийся define

Здравствуйте.

 

Написан конечный автомат на конструкции switch - case. Для перехода к последующему действию просто инкрементируется указатель:

switch(i)
{
case 0: ... i++;
case 1: ... i++;
...
case N: ... i++;
}

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

 

Хочется перенести эту задачу на плечи препроцессора и оформить конструкцию таким образом, чтобы название макроопределения case было у всех одинаковым и, в тоже время, каждое последующее значение было на 1 больше предыдущего:

switch(i)
{
case INCNAME: ... i++;
case INCNAME: ... i++;
...
case INCNAME: ... i++;
}

Подскажите, пожалуйста, возможно ли это как-то реализовать?

Спасибо.

Share this post


Link to post
Share on other sites

Так получится?

int j = 0;

if(0){}
else if((j++) && (i == j))
{
  // do 1
  i++;
}
else if((j++) && (i == j))
{
  // do 2
  i++;
}
...
else if((j++) && (i == j))
{
  // do N
  i++;
}

 

#define NEXT else if((j++) && (i==j))

if(0){}
NEXT
{
}
NEXT
{
}

Share this post


Link to post
Share on other sites

"В лоб" задача решается применением enum.

typedef enum
{
      IDLE,
      START,
      RUN,
      STOP
} state_t;

state_t State;


switch (State)
{
case IDLE:
    .....
    State = START;
    break;

case START:
    ....

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

Share this post


Link to post
Share on other sites
Действий порядка 100 и возникла проблема с добавлением новых case-обработчиков в середину конструкции, т.к. приходится увеличивать все последующие номера case.

Хочется перенести эту задачу на плечи препроцессора и оформить конструкцию таким образом, чтобы название макроопределения case было у всех одинаковым и, в тоже время, каждое последующее значение было на 1 больше предыдущего:

Значения после case должны быть разными. Иначе компилятор просто не станет компилить.

Я в подобных случаях использую enum. При добавлении хоть в середину хоть в конец нет проблем с перенумерацией.

enum { //фазы автомата состояний

INCNAME_SOST0, INCNAME_SOST1, INCNAME_SOST2, ...};

 

Так получится?

else if((j++) && (i == j))

...

Не компилил, но почти уверен, что на такую конструкцию компилятор скажет: "Undefined behavior".

Share this post


Link to post
Share on other sites
Не компилил, но почти уверен, что на такую конструкцию компилятор скажет: "Undefined behavior".

Компилируется даже без предупреждений.

Единственное, в {} не должно быть i++.

Лучше new_i++, а в самом конце i = new_i.

Иначе автомат выстрелит очередью.

Share this post


Link to post
Share on other sites
Подскажите, пожалуйста, возможно ли это как-то реализовать?

Спасибо.

Создаете в Excel одну строку с одним макроопределением.

Потом протягиваете ее до 100 строк и получаете идеальный инкремент.

Если нужно вставить что-то в середину, то в вставляете в Excel-е и снова протягиваете, получите новый инкремент.

Потом Copy-Paste из Excel-а

post-2050-1468138160_thumb.png

 

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

Share this post


Link to post
Share on other sites

Подход с enum, несомненно, правилен.

Однако, при добавлении состояний, потребуется редактировать в двух местах.

#define INCNAME __COUNTER__

Только надо предусмотреть ловушку какую на случай если __COUNTER__ был ранее использован.

https://gcc.gnu.org/onlinedocs/cpp/Common-P...edefined-Macros

Share this post


Link to post
Share on other sites
Действий порядка 100...

Что говорит о том, что решение поставленной задачи только с помощью конечного автомата зашло в тупик :(.

Думайте о комбинации методов. Более-менее типичный выход из такой ситуации это использование наряду с состоянием конечного автомата дополнительных битовых флагов.

 

Share this post


Link to post
Share on other sites
Что говорит о том, что решение поставленной задачи только с помощью конечного автомата зашло в тупик :(.

Думайте о комбинации методов.

Да нормально, есть прикладные протоколы с очень большими словарями.

 

Только вот enum для этого негодное средство,

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

Share this post


Link to post
Share on other sites
Да нормально, есть прикладные протоколы с очень большими словарями.

Не путайте протоколы с их РЕАЛИЗАЦИЕЙ через анус. Сотня состояний конечного автомата это уже анус.

Только вот enum для этого негодное средство,

поскольку при отладке...

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

Так что логирование состояния конечного автомата обязательно, ну а при логировании разворачивание названий состояний в текст так же обязательно. Все это решается через общую функцию изменения состояния автомата. Например:

void q921_set_state( LAPD_t *ldp, ulong new_state  )
{
    ldp->state =  new_state;
    dprintf( "\tL%1X:Set State`%s`(Cmd:%4X)\r", ldp->ch, q2_states[ldp->state], ldp->q921_cmd );
}

Share this post


Link to post
Share on other sites
Не путайте протоколы с их РЕАЛИЗАЦИЕЙ через анус. Сотня состояний конечного автомата это уже анус.

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

Прямо сейчас у меня в работе протокол с 41-им case в парсере.

 

Линейная структура кода позволяет легко его форматировать и рефакторить.

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

Работает она быстрее.

Короче одни плюсы. :biggrin:

 

Протоколы только отладчиком через SWD и можно детально отладить.

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

Share this post


Link to post
Share on other sites
Только вот enum для этого негодное средство,

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

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

 

Share this post


Link to post
Share on other sites
Мой отладчик пишет численное значение при помещени указателя мыши на имя.

 

Трудно припомнить название? :biggrin:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this