Tahoe 0 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба Суть вопроса, на примере управления светодиодом. Декларация структуры, с "методом" 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; Но может есть какой-то более элегантный способ? Речь о чистых Сях. Варианты в духе "написать на плюсах" или "не париться" известны и не интересны - заранее привет от К.О. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 10 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба ui.led[0].mode = UI_LED_MODE_FLSH_SHRT; А по таймеру смотреть состояния всех led и включать/выключать/мигать нужными. Так не устроит? Что должна делать set()? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tahoe 0 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба Что должна делать 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()... :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 10 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба Может, я не прав, но стараюсь в отношении Си придерживаться принципа: управляй данными, а не кодом. Т.е. минимизирую число функций, а структуры данных использую по максимуму. В структурах данных могу хранить адреса callback-функций, когда это важно. Обработку кнопок и светодиодов провожу в системном таймере. Изменение состояний светодиодов произвожу через данные структуры. Считывание состояний кнопок можно проводить через данные структуры, а можно через callback-функции. Вы же рассматриваете светодиоды и кнопки как объекты (т.е. данные и код для обработки этих данных) - вам прямой путь в плюсы. Или делать по аналогии .set(&led[0], NEW_STATE) передавая явно указатель на объект (а не его номер). Причем, сегодня вам не хватает this, а завтра захочется наследования и полиморфизма) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tahoe 0 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба Обработку кнопок и светодиодов провожу в системном таймере. Аналогично. Hook вызывается из SysTick_Handler(), это системный таймер. Изменение состояний светодиодов произвожу через данные структуры. Если я правильно понял, то речь скорее идет о способе управления, поллинг или событийно. Другими словами, либо сразу установить состояние светодиода, либо установить в памяти бит где-то в структуре, который периодически опрашивается. Иначе, не вижу расхождений. Вы же рассматриваете светодиоды и кнопки как объекты (т.е. данные и код для обработки этих данных) - вам прямой путь в плюсы. Такие вещи, как светодиоды/кнопки и еще много других, используются в 9 проектах из 10. Какие-то проекты допустимо исполнить на плюсах, но в основном, заказчики хотят чистый Си. Делать по две реализации каждого драйвера, каждого сервиса - совсем не хочется. Да и почему бы не выжать из Сей максимум его возможностей? :) Причем, сегодня вам не хватает this, а завтра захочется наследования и полиморфизма) Не, я не маргинал. Я умеренный перфекционист. Если что-то имеется в наличии и можно задействовать ( ну просто я об этом не знаю, век живи - век учись ), то почему бы нет. :) Или делать по аналогии .set(&led[0], NEW_STATE) передавая явно указатель на объект (а не его номер). А тогда не вижу особого смысла городить "метод" - разумнее оставить все как есть, обычный вызов функции, с парой аргументов. Если посмотреть, то у set() есть два аргумента, первый константа, причем известная на этапе компиляции, второй переменная. Т.е. задача, выходит, сводится к тому, что бы подпихнуть эту константу и полностью скрыть первый аргумент. Выходит, что это должно быть две функции, собственно метод и его обертка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 10 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба Т.е. задача, выходит, сводится к тому, что бы подпихнуть эту константу и полностью скрыть первый аргумент. Выходит, что это должно быть две функции, собственно метод и его обертка. К сожалению я тоже не смог найти способа передавать аналог this, поэтому везде приходится таскать первый параметр в функциях (в тех же callback-ах). Идеально было бы иметь аналог __LINE__, __FILE__, например, __THIS__ который бы заполнялся адресом вызывавшей структуры. Но нигде такого не встречал. Может, знатоки знают про потайные места gcc?... на уровне компилятора это не сложно сделать. Кста, это вряд ли будет стандарт Си, скорее какая-нить надстройка компилятора. Вам под компилятор какой если что? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tahoe 0 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба Кста, это вряд ли будет стандарт Си, скорее какая-нить надстройка компилятора. Вам под компилятор какой если что? Мне под IAR. Но не хочется использовать специфику того или иного компилера. Хотелось бы решить средствами языка, причем: - не сильно в ущерб читаемости кода - возможно задействовав препроцессор, но не в форме жесткого изврата, как, например, в известном коде меню для индикаторов - не убивая контроль за ошибками, то бишь без всяких (void *) Никогда не сталкивался на практике с Objective-C, но насколько знаю, он ближе к Сям. В этом смысле, интересен уже имеющийся опыт: Difference b/w Objective C's self and C++'s this? Пессимистично. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 7 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба int gLedIndex; ....... #define LED0 (gLedIndex = 0) #define LED1 (gLedIndex = 1) ....... ui.led[ LED0 ].set( UI_LED_MODE_FLSH_SHRT ); и уже в функции set по состоянию глобальной переменной gLedIndex можно понять, для какого светодиода вызвана эта функция. Очень опасно для многопоточных приложений (надо внимательно разделять ресурс светодиодов), и не this конечно, но вполне читабельно и наглядно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tahoe 0 4 июля, 2015 Опубликовано 4 июля, 2015 · Жалоба и уже в функции set по состоянию глобальной переменной gLedIndex можно понять, для какого светодиода вызвана эта функция. Очень опасно для многопоточных приложений (надо внимательно разделять ресурс светодиодов), и не this конечно, но вполне читабельно и наглядно. На первый взгляд - вариант. Но действительно стремный, т.к. придется на пустом месте обрамлять ENTR_CRITICAL()/EXIT_CRITICAL() плюс лочить переменную. Для светодиодов, пожалуй, прокатит. Но, скажем, с несколькими устройствами на одном SPI будет нехорошо. Хотя, по-сути, это разновиднсть варианта с добавлением поля "n", описанного в первом посте. Чуть меньше расход памяти и чуть больше проблем. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться