| Микроконтролери и електроника http://mcu-bg.com/mcu_site/ |
|
| Един С въпрос http://mcu-bg.com/mcu_site/viewtopic.php?f=3&t=506 |
Страница 1 от 2 |
| Автор: | Цецо [ Сря Мар 23, 2005 3:15 pm ] |
| Заглавие: | Един С въпрос |
Значи имам да пиша тестов софтуер за едни платки. Програмата се състои от около 100 тина теста, които не подлежат на някакво кое знае какво унифициране. Всеки ще е в отделна функция. Не са последователни, изпълняват се при команда от PC. Как предлагате да реализирам викането на функциите? Най-простото решение ми се струва SWITCH,CASE, ама 100 броя изглежда малко дървено. Някакво по хитро решение да се сещате? |
|
| Автор: | ¶ [ Сря Мар 23, 2005 3:41 pm ] |
| Заглавие: | |
Ако компилатора на C, който ще използваш, поддържа указатели към функции, ще стане най-елегантно. Правиш един масив от указатели към функции, след което по кода на командата адресираш масива и се изпълнява съответната функция. Кодовете на командите трябва да са последователни числа в даден обхват, не е задължително да започват от нула. Например: typedef bool (*ParseCommand)(void); ParseCommand ParseCommandFunction [ NUMBER_OF_COMMAND ] = { ParseCommand1, ParseCommand2, ParseCommand3, ParseCommand4,ParseCommand5, ParseCommand6, ParseCommand7, ParseCommand8,ParseCommand9, ParseCommand10, ParseCommand11, ParseCommand12,ParseCommand13, ParseCommand14, ParseCommand15, ParseCommand16,ParseCommand17, ParseCommand18, ParseCommand19, ParseCommand20, ParseCommand21, ParseCommand22, ParseCommand23, #ifdef USE_LAMP_MONITORING ParseCommand24, ParseCommand25, ParseCommand26, #endif #ifdef USE_PERCENT_BURN_OUT ParseCommand27 #endif }; После извикваш дадена функция така: ParseCommandFunction[cmd.Buffer[5]-1](); Преди обаче да извикаш дадена функция от масива, провери индекса на масива дали е в обхвата, иначе лошо Цитирания фрагмент от програма е от работеща програма за TCP/IP мрежа, компилирана с Borland C++ 5.02 и работи безотказно под Windows XP 2-ра година. |
|
| Автор: | ¶ [ Сря Мар 23, 2005 3:48 pm ] |
| Заглавие: | |
Хрумна и още нещо: ако кодовете на командите, получавани от ПК не са последователни числа, правиш си пак масива с функции и там където има непоследователни кодове слагаш някаква фиктивна функция, която няма да върши нищо: ParseCommand ParseCommandFunction[ NUMBER_OF_COMMAND ] = { ParseCommand1, FicticiousFunction,FicticiousFunction,FicticiousFunction, ParseCommand5,ParseCommand6, ParseCommand7, ParseCommand8,ParseCommand9, ParseCommand10, ParseCommand11, ParseCommand12,ParseCommand13, ParseCommand14, ParseCommand15, ParseCommand16,ParseCommand17, ParseCommand18, ParseCommand19, ParseCommand20, ParseCommand21, ParseCommand22, ParseCommand23, #ifdef USE_LAMP_MONITORING ParseCommand24, ParseCommand25, ParseCommand26, #endif #ifdef USE_PERCENT_BURN_OUT ParseCommand27 #endif }; За код команда 2,3 и 4 се извикава фиктивната функция. |
|
| Автор: | bateAz [ Сря Мар 23, 2005 4:05 pm ] |
| Заглавие: | |
С масив от указатели към финкциите. Това ще да е най-смисленото и най-прегледното показване на нещата. И най-лесно се коригира при нужда. |
|
| Автор: | Реконструктор [ Сря Мар 23, 2005 5:17 pm ] | |||||||||
| Заглавие: | ||||||||||
По принцип, ако търсиш най-лесното, то то е да си наредиш ф-иите през реавно разстояние. Ако, разбира се, не пестиш място и компилатора ти го позволява. С масива от указатели има един проблем, и той е, че когато отпадне някоя от ф-иите, в масива се образува дупка и той трябва да се преиндексира целия. За това има 2 подхода. Най-простия е ф-ята да се вика от ф-я посредник, която да проверява за дупки.
Другия начин е не масив, ами списък, който при повече желание може да се направи да имитира масив, но това май вече не е за тебе. Добре е и да се измислят хитри макросчета, така, че адреса на ф-ята да се добавя към масива още при нейното декларириране, това ще опрости малко работата. |
||||||||||
| Автор: | ¶ [ Сря Мар 23, 2005 6:05 pm ] |
| Заглавие: | |
Реконструктор, не ми стана ясно, как след като отпадне някоя функция от масива ще се изпълни условието за NULL във функцията посредник. Нали веднага компилатара ще замести нейната позиция със следващата функция в масива, освен ако на позицията на отпадналата функция в масива не запишеш NULL. Ами то след като ще записваш все пак нещо на тази позиция в масива (т.е. заемаш памет ), защо да не е адреса на фиктивната функция ? Дори у да объркаш нещо в индексите на масива ще се извика коректно фиктивната функция. Освен това е задължително във функцията посредник да правиш проверка за обхвата на nIndex, тъй като nIndex ще е променлива получавана от външния свят, т.е. проверката: if (arr_functions[nIndex] != NULL) arr_functions[nIndex](); може и да не се изпълни коректно, ако nIndex е по-голям от максималния размер на масива и ще извикаш функция от произволно място в паметта, ако след края на масива в паметта имаш данни различни от NULL. Според мен, ако ще се записва на мястото на липсваща команда в масива от функции NULL, проверката трябва да е следната: #define MAX_ARRAY_OF_FUNCTION 10 void CallFunction(short nIndex) { if( nIndex < MAX_ARRAY_OF_FUNCTION && arr_functions[nIndex] != NULL ) arr_functions[nIndex](); } За списък е удобно, ама човека питаше за платки, следователно според мен става дума за едночипов микроконтолер и надали ще може да си позволи харченене на RAM за организиране на списък. А и да задам и един глупав въпрос: Как го оцветявате програмния код, така че да се различава от останалия текст в съобщенията от форума ? |
|
| Автор: | Реконструктор [ Сря Мар 23, 2005 6:20 pm ] |
| Заглавие: | |
Колега, обсъждаш незначителни подробности. Опитай се да адресираш несъществуваща ф-я, компилатора ще изгърми веднага. Та за това на мястото на адреса на тая несъществуваща ф-я слагаш NULL. Другия начин, както съм написал в предишния си пост, е да преиндексираш целия масив, като съответно трябва да съобразиш това със софтуера на ПЦ-то и изобщо е излишно напъване. По повод на оцветяването - извършва се като натиснеш бутона Code, който се намира над полето, в което пишеш. |
|
| Автор: | ¶ [ Сря Мар 23, 2005 6:38 pm ] | |||||||||
| Заглавие: | ||||||||||
Реконструктор, не се заяждам, но да бъдем точни и коректни в отговорите си ! По повод на "незначителните подробности" изпробвай следния код и виж какво ще стане.
|
||||||||||
| Автор: | Dimitar [ Сря Мар 23, 2005 8:45 pm ] |
| Заглавие: | |
Ама много го задълбавате, я да си сложи човека switch и case-вете и да не се мъчи |
|
| Автор: | Nikola Kirov [ Съб Мар 26, 2005 2:02 pm ] |
| Заглавие: | |
Аз наскоро писах подобно нещо.Имах над 70 функции. За да се работи прегледно и удобно ги разбих на 4 групи които са с отделен swich-case. Правих програматор и се налагаше да гоня и бързина така че сравнявах бързодеиствие с друг вариант които бях направил с масив с указатели. Оказа се че резултатите са сходни. Просто варианта с swich-case е по лесен за настроиване и модификация |
|
| Автор: | Цецо [ Съб Мар 26, 2005 6:57 pm ] |
| Заглавие: | |
Е не би трябвало резултата по бързодействие да е сходен. SWITCH - CASE минава през всички CASE-ове докато стигне до подходящия. Масива с указатели би трябвало да работи със сумиране+индексиране. Нещо по-важно времето за достъп до функцията при втория метод би трябвало да е константен докато при първия времето расте с номера на функцията. Така си мисля. Ще експериментирам и двата варианта. Не съм сигурен че компилатора ми поддържа указатели към функция - не че е нещо сложно, ама за MPLAB C18 иде реч. |
|
| Автор: | Nikola Kirov [ Съб Мар 26, 2005 9:01 pm ] |
| Заглавие: | |
Идеята с разбиването на групи е че първо проверяваш в кои блок е съответната функция и предаваш управлението в съответния swich-case. Taka при мен се получи че максималното време за изпълнение беше незначително повече при този метод.Но затова пък по удобно. |
|
| Автор: | ToHu [ Съб Мар 26, 2005 9:52 pm ] |
| Заглавие: | |
Хммм не е точно така за switch-а .. компилатора си го оптимизира по самите стойности в switch и ако са типоследователни го изпълнява не с проверка на всички докато открие разлика, ами с указател. |
|
| Автор: | Nikola Kirov [ Нед Мар 27, 2005 1:45 am ] |
| Заглавие: | |
Виж за това не знам. Разбиването на групи го правих за мое удобство наи вече. А го правих за PC и не съм следил какво генерира компилатора. Просто засичах времената за изпълнение и се оказа че разликата е съвсем малка. |
|
| Автор: | ¶ [ Нед Мар 27, 2005 2:14 am ] |
| Заглавие: | |
Масива от указатели има и друго предимство, а то е когато програмата се пише от колектив ( можеш да раздадеш на отделните програмисти кои функции да напишат ) , или пък когато за по лесното поддържане на софтуера е нужно отделните функции да са в различни файлове, по смислово съдържание, а пък и програмата е по прегледна с масива от функции. Бързодействието зависи от компилатора, процесора и дали case-вете са последователни числа ( ако са последователни числа, добрите компилатори реализират таблица с jmp към съответния case ). Най-добре е да се направи тестова програма, реализираща и двата варианта и да се види какво генерира компилатора. Обаче използваш ли масив, прави проверка за обхвата на индекса, защото никой C/C++ компилатор не се интересува дали извикваната функция има нулев(NULL) или различен от нула адрес ( в някои процесори на нулев адрес има системни подпрограми ) MCC18 компилатора поддържа указатели към функции. |
|
| Страница 1 от 2 | Часовете са според зоната UTC + 2 часа [ DST ] |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|