|
|
  |
Как бы организовать в Сях аналог self/this? |
|
|
|
Jul 4 2015, 04:56
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Суть вопроса, на примере управления светодиодом. Декларация структуры, с "методом" 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; Но может есть какой-то более элегантный способ? Речь о чистых Сях. Варианты в духе "написать на плюсах" или "не париться" известны и не интересны - заранее привет от К.О.
|
|
|
|
|
Jul 4 2015, 05:51
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(adnega @ Jul 4 2015, 08:13)  Что должна делать 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()...
|
|
|
|
|
Jul 4 2015, 06:34
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Может, я не прав, но стараюсь в отношении Си придерживаться принципа: управляй данными, а не кодом. Т.е. минимизирую число функций, а структуры данных использую по максимуму. В структурах данных могу хранить адреса callback-функций, когда это важно.
Обработку кнопок и светодиодов провожу в системном таймере. Изменение состояний светодиодов произвожу через данные структуры. Считывание состояний кнопок можно проводить через данные структуры, а можно через callback-функции.
Вы же рассматриваете светодиоды и кнопки как объекты (т.е. данные и код для обработки этих данных) - вам прямой путь в плюсы. Или делать по аналогии .set(&led[0], NEW_STATE) передавая явно указатель на объект (а не его номер). Причем, сегодня вам не хватает this, а завтра захочется наследования и полиморфизма)
|
|
|
|
|
Jul 4 2015, 07:22
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(adnega @ Jul 4 2015, 09:34)  Обработку кнопок и светодиодов провожу в системном таймере. Аналогично. Hook вызывается из SysTick_Handler(), это системный таймер. Цитата(adnega @ Jul 4 2015, 09:34)  Изменение состояний светодиодов произвожу через данные структуры. Если я правильно понял, то речь скорее идет о способе управления, поллинг или событийно. Другими словами, либо сразу установить состояние светодиода, либо установить в памяти бит где-то в структуре, который периодически опрашивается. Иначе, не вижу расхождений. Цитата(adnega @ Jul 4 2015, 09:34)  Вы же рассматриваете светодиоды и кнопки как объекты (т.е. данные и код для обработки этих данных) - вам прямой путь в плюсы. Такие вещи, как светодиоды/кнопки и еще много других, используются в 9 проектах из 10. Какие-то проекты допустимо исполнить на плюсах, но в основном, заказчики хотят чистый Си. Делать по две реализации каждого драйвера, каждого сервиса - совсем не хочется. Да и почему бы не выжать из Сей максимум его возможностей?  Цитата(adnega @ Jul 4 2015, 09:34)  Причем, сегодня вам не хватает this, а завтра захочется наследования и полиморфизма) Не, я не маргинал. Я умеренный перфекционист. Если что-то имеется в наличии и можно задействовать ( ну просто я об этом не знаю, век живи - век учись ), то почему бы нет.  Цитата(adnega @ Jul 4 2015, 09:34)  Или делать по аналогии .set(&led[0], NEW_STATE) передавая явно указатель на объект (а не его номер). А тогда не вижу особого смысла городить "метод" - разумнее оставить все как есть, обычный вызов функции, с парой аргументов. Если посмотреть, то у set() есть два аргумента, первый константа, причем известная на этапе компиляции, второй переменная. Т.е. задача, выходит, сводится к тому, что бы подпихнуть эту константу и полностью скрыть первый аргумент. Выходит, что это должно быть две функции, собственно метод и его обертка.
|
|
|
|
|
Jul 4 2015, 07:30
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Tahoe @ Jul 4 2015, 10:22)  Т.е. задача, выходит, сводится к тому, что бы подпихнуть эту константу и полностью скрыть первый аргумент. Выходит, что это должно быть две функции, собственно метод и его обертка. К сожалению я тоже не смог найти способа передавать аналог this, поэтому везде приходится таскать первый параметр в функциях (в тех же callback-ах). Идеально было бы иметь аналог __LINE__, __FILE__, например, __THIS__ который бы заполнялся адресом вызывавшей структуры. Но нигде такого не встречал. Может, знатоки знают про потайные места gcc?... на уровне компилятора это не сложно сделать. Кста, это вряд ли будет стандарт Си, скорее какая-нить надстройка компилятора. Вам под компилятор какой если что?
|
|
|
|
|
Jul 4 2015, 07:55
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(adnega @ Jul 4 2015, 10:30)  Кста, это вряд ли будет стандарт Си, скорее какая-нить надстройка компилятора. Вам под компилятор какой если что? Мне под IAR. Но не хочется использовать специфику того или иного компилера. Хотелось бы решить средствами языка, причем: - не сильно в ущерб читаемости кода - возможно задействовав препроцессор, но не в форме жесткого изврата, как, например, в известном коде меню для индикаторов - не убивая контроль за ошибками, то бишь без всяких (void *) Никогда не сталкивался на практике с Objective-C, но насколько знаю, он ближе к Сям. В этом смысле, интересен уже имеющийся опыт: Difference b/w Objective C's self and C++'s this?Пессимистично.
|
|
|
|
|
Jul 4 2015, 09:31
|
Знающий
   
Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088

|
Код int gLedIndex; ....... #define LED0 (gLedIndex = 0) #define LED1 (gLedIndex = 1) ....... ui.led[ LED0 ].set( UI_LED_MODE_FLSH_SHRT ); и уже в функции set по состоянию глобальной переменной gLedIndex можно понять, для какого светодиода вызвана эта функция. Очень опасно для многопоточных приложений (надо внимательно разделять ресурс светодиодов), и не this конечно, но вполне читабельно и наглядно.
--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
|
|
|
|
|
Jul 4 2015, 10:49
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(gerber @ Jul 4 2015, 12:31)  и уже в функции set по состоянию глобальной переменной gLedIndex можно понять, для какого светодиода вызвана эта функция. Очень опасно для многопоточных приложений (надо внимательно разделять ресурс светодиодов), и не this конечно, но вполне читабельно и наглядно. На первый взгляд - вариант. Но действительно стремный, т.к. придется на пустом месте обрамлять ENTR_CRITICAL()/EXIT_CRITICAL() плюс лочить переменную. Для светодиодов, пожалуй, прокатит. Но, скажем, с несколькими устройствами на одном SPI будет нехорошо. Хотя, по-сути, это разновиднсть варианта с добавлением поля "n", описанного в первом посте. Чуть меньше расход памяти и чуть больше проблем.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|