Перейти к содержанию
    

Как бы организовать в Сях аналог self/this?

Суть вопроса, на примере управления светодиодом. Декларация структуры, с "методом" set:

 

typedef    enum    ui_led_mode_e
{
    UI_LED_MODE_OFF,
    UI_LED_MODE_ON,
    UI_LED_MODE_TOGGLE,
    UI_LED_MODE_FLSH_LONG,
    UI_LED_MODE_FLSH_SHRT,
}    ui_led_mode_t;

typedef    void    ( * ui_led_set_t )(            ui_led_mode_t        mode        );

typedef    struct    ui_led_s
{
    ui_led_set_t      set;
    size_t            tick;
}    ui_led_t;

typedef    struct    ui_s
{
    ui_led_t            led[ 2 ];
}    ui_t;

 

Использование:

 

ui_t        ui;

void    main(                                void                            )
{
    ui_init();

    while( 1 )
    {
        ui.led[ 0 ].set(    UI_LED_MODE_FLSH_SHRT                    );
        delay_msec( 500 );
    }
}

 

Проблема возникает при реализации ui_led_set(). А именно, как ui_led_set() узнать, откуда пришел вызов? Из ui.led[0].set() или из ui.led[1].set?

 

Тупое:

 

ui.led[ 0 ].set( 0, UI_LED_MODE_FLSH_SHRT );

ui.led[ 1 ].set( 1, UI_LED_MODE_FLSH_SHRT );

 

сколь очевидно, столь и не интересно, поскольку суть вопроса в аналоге self/this, а не передавать каждый раз извне. В голове крутится, как-то сыграть на том, что ui это глобальная/статическая переменная. Но как именно - не соображу.

 

Можно, конечно, добавить в структуру поле "n" и при инициализации, ручками, пронумеровать все стркутуры в массиве:

 

typedef    struct    ui_led_s
{
    size_t            n;
    ui_led_set_t      set;
    size_t            tick;
}    ui_led_t;

 

Но может есть какой-то более элегантный способ?

 

Речь о чистых Сях. Варианты в духе "написать на плюсах" или "не париться" известны и не интересны - заранее привет от К.О. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ui.led[0].mode = UI_LED_MODE_FLSH_SHRT;

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

Так не устроит? Что должна делать set()?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что должна делать set()?

На всяк.случ. повторюсь, управление светодиодом взято в качестве примера. Аналогично работает, скажем, опрос кнопок. Но по-большому счету, в любом проекте полно других структур.

 

void    SysTick_Handler(                    void                            )
{
    ....
    app.event.ui_key    =    ui_key_systick_hook(    &ui.key        );
    app.event.ui_led    =    ui_led_systick_hook(    &ui.led        );
    ....
}

 

Так выглядит hook:

 

bool    ui_led_systick_hook(                ui_led_t *            p            )
{
    bool            resp    =    false;

    if( p->tick > 0 )
    {
        if( --(p->tick) == 0 )
        {
            ui_led_toggle();
            resp    =    true;
        }
    }

    return( resp );
}

 

Ну и, собственно, сам метод:

 

void    ui_led_set(                            ui_led_t *            p,
                                    const    ui_led_mode_t        mode        )
{
    switch( mode )
    {
        case    UI_LED_MODE_OFF:
            bsp_led_set( false );
            break;

        case    UI_LED_MODE_ON:
            bsp_led_set( true );
            break;

        case    UI_LED_MODE_TOGGLE:
            ui_led_toggle();
            break;

        case    UI_LED_MODE_FLSH_LONG:
            if( p->tick == 0 )
            {
                ui_led_toggle();
            }
            p->tick        =    UI_LED_FLSH_LONG_TCKS;
            break;

        case    UI_LED_MODE_FLSH_SHRT:
            if( p->tick == 0 )
            {
                ui_led_toggle();
            }
            p->tick        =    UI_LED_FLSH_SHRT_TCKS;
            break;

        default:
            break;
    }
}

 

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

 

ui_led_set(  &ui.led0, UI_LED_MODE_FLSH_SHRT );
ui_led_set(  &ui.led[0], UI_LED_MODE_FLSH_SHRT );

 

вызывать, как написал в первом посте:

 

ui.led[ 0 ].set(    UI_LED_MODE_FLSH_SHRT                    );

 

Но что-то мне подсказывает, что средствами языка, без хаков и извратов, сделать это не получится. Тогда, видимо, остается только вариант, описаный мною выше - добавить в структуру переменную n. Ну либо совсем чернуха, в духе ui_led_set_0(), ui_led_set_1()... :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может, я не прав, но стараюсь в отношении Си придерживаться принципа: управляй данными, а не кодом.

Т.е. минимизирую число функций, а структуры данных использую по максимуму.

В структурах данных могу хранить адреса callback-функций, когда это важно.

 

Обработку кнопок и светодиодов провожу в системном таймере. Изменение состояний светодиодов

произвожу через данные структуры. Считывание состояний кнопок можно проводить через данные структуры,

а можно через callback-функции.

 

Вы же рассматриваете светодиоды и кнопки как объекты (т.е. данные и код для обработки этих данных) - вам прямой путь в плюсы.

Или делать по аналогии .set(&led[0], NEW_STATE) передавая явно указатель на объект (а не его номер).

Причем, сегодня вам не хватает this, а завтра захочется наследования и полиморфизма)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обработку кнопок и светодиодов провожу в системном таймере.

Аналогично. Hook вызывается из SysTick_Handler(), это системный таймер.

 

Изменение состояний светодиодов

произвожу через данные структуры.

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

 

Вы же рассматриваете светодиоды и кнопки как объекты (т.е. данные и код для обработки этих данных) - вам прямой путь в плюсы.

Такие вещи, как светодиоды/кнопки и еще много других, используются в 9 проектах из 10. Какие-то проекты допустимо исполнить на плюсах, но в основном, заказчики хотят чистый Си. Делать по две реализации каждого драйвера, каждого сервиса - совсем не хочется. Да и почему бы не выжать из Сей максимум его возможностей? :)

 

Причем, сегодня вам не хватает this, а завтра захочется наследования и полиморфизма)

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

 

Или делать по аналогии .set(&led[0], NEW_STATE) передавая явно указатель на объект (а не его номер).

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Идеально было бы иметь аналог __LINE__, __FILE__, например, __THIS__ который бы заполнялся адресом вызывавшей структуры.

Но нигде такого не встречал. Может, знатоки знают про потайные места gcc?... на уровне компилятора это не сложно сделать.

Кста, это вряд ли будет стандарт Си, скорее какая-нить надстройка компилятора. Вам под компилятор какой если что?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кста, это вряд ли будет стандарт Си, скорее какая-нить надстройка компилятора. Вам под компилятор какой если что?

Мне под IAR. Но не хочется использовать специфику того или иного компилера. Хотелось бы решить средствами языка, причем:

- не сильно в ущерб читаемости кода

- возможно задействовав препроцессор, но не в форме жесткого изврата, как, например, в известном коде меню для индикаторов

- не убивая контроль за ошибками, то бишь без всяких (void *)

 

Никогда не сталкивался на практике с Objective-C, но насколько знаю, он ближе к Сям. В этом смысле, интересен уже имеющийся опыт:

Difference b/w Objective C's self and C++'s this?

Пессимистично.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

int gLedIndex;
.......
#define LED0  (gLedIndex = 0)
#define LED1  (gLedIndex = 1)
.......
ui.led[ LED0 ].set( UI_LED_MODE_FLSH_SHRT );

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

Хотя, по-сути, это разновиднсть варианта с добавлением поля "n", описанного в первом посте. Чуть меньше расход памяти и чуть больше проблем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...