|
Виж темите без отговор | Виж активните теми
Дата и час: Пон Юли 27, 2026 2:23 pm
| Автор |
Съобщение |
|
Цецо
Ранг: Форумен бог
Регистриран на: Пон Сеп 27, 2004 9:22 am Мнения: 15501 Местоположение: София
|
 Един С въпрос
Значи имам да пиша тестов софтуер за едни платки. Програмата се състои от около 100 тина теста, които не подлежат на някакво кое знае какво унифициране. Всеки ще е в отделна функция. Не са последователни, изпълняват се при команда от PC. Как предлагате да реализирам викането на функциите? Най-простото решение ми се струва SWITCH,CASE, ама 100 броя изглежда малко дървено. Някакво по хитро решение да се сещате?
_________________ "Да еба и шибаната държава" мислеше си Гошо, докато се опитваше да улучи кофата за боклук от балкона на осмия етаж.
|
| Сря Мар 23, 2005 3:15 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Ако компилатора на 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:41 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Хрумна и още нещо: ако кодовете на командите, получавани от ПК не са последователни числа, правиш си пак масива с функции и там където има непоследователни кодове слагаш някаква фиктивна функция, която няма да върши нищо:
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 се извикава фиктивната функция.
|
| Сря Мар 23, 2005 3:48 pm |
|
 |
|
bateAz
Ранг: Форумен бог
Регистриран на: Нед Сеп 26, 2004 4:11 pm Мнения: 3750 Местоположение: София
|
С масив от указатели към финкциите. Това ще да е най-смисленото и най-прегледното показване на нещата. И най-лесно се коригира при нужда.
|
| Сря Мар 23, 2005 4:05 pm |
|
 |
|
Реконструктор
Ранг: Форумен бог
Регистриран на: Съб Сеп 25, 2004 12:32 pm Мнения: 8382 Местоположение: София
|
По принцип, ако търсиш най-лесното, то то е да си наредиш ф-иите през реавно разстояние. Ако, разбира се, не пестиш място и компилатора ти го позволява.
С масива от указатели има един проблем, и той е, че когато отпадне някоя от ф-иите, в масива се образува дупка и той трябва да се преиндексира целия. За това има 2 подхода. Най-простия е ф-ята да се вика от ф-я посредник, която да проверява за дупки.
Другия начин е не масив, ами списък, който при повече желание може да се направи да имитира масив, но това май вече не е за тебе.
Добре е и да се измислят хитри макросчета, така, че адреса на ф-ята да се добавя към масива още при нейното декларириране, това ще опрости малко работата.
|
| Сря Мар 23, 2005 5:17 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Реконструктор, не ми стана ясно, как след като отпадне някоя функция от масива ще се изпълни условието за 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:05 pm |
|
 |
|
Реконструктор
Ранг: Форумен бог
Регистриран на: Съб Сеп 25, 2004 12:32 pm Мнения: 8382 Местоположение: София
|
Колега, обсъждаш незначителни подробности. Опитай се да адресираш несъществуваща ф-я, компилатора ще изгърми веднага. Та за това на мястото на адреса на тая несъществуваща ф-я слагаш NULL. Другия начин, както съм написал в предишния си пост, е да преиндексираш целия масив, като съответно трябва да съобразиш това със софтуера на ПЦ-то и изобщо е излишно напъване.
По повод на оцветяването - извършва се като натиснеш бутона Code, който се намира над полето, в което пишеш.
|
| Сря Мар 23, 2005 6:20 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Реконструктор, не се заяждам, но да бъдем точни и коректни в отговорите си ! По повод на "незначителните подробности" изпробвай следния код и виж какво ще стане.
 |  |  |  | Код: typedef bool (*ParseCommand)(void);
bool Func1(void) { return true; }
bool Func2(void) { return false; }
bool Func3(void) { return true; }
const int cNumberOfFunctions = 3;
ParseCommand ArrayOfFunctions[cNumberOfFunctions] = { Func1, Func2, Func3
};
int main(int /*argc*/,char **/*argv*/) {
int nIndex; // Извиквам в долния код в цикъл функциите от масива ArrayOfFunctions, // но умишлено допускам грешка с конструкцията nIndex < ( cNumberOfFunctions + 1 ) // при което никой C/C++ няма да ви даде че имате грешка при компилация, т.е. // компилатора Ви няма да гръмне, а ще гръмне вашата програма по време // на изпълнение, защото ще извикате несъществуваща функция ! Компилаторите на // C/C++ не правят проверка за размерността на масивите когато ги индексирате, // Тази проверка си я прави програмиста, освен ако масива не е реализиран // като class в C++, при което може да предефинирате оператори, които да // вършат тази работа. for( nIndex = 0; nIndex < (cNumberOfFunctions+1); nIndex++ ) ArrayOfFunctions[nIndex]();
} |  |  |  |  |
|
| Сря Мар 23, 2005 6:38 pm |
|
 |
|
Dimitar
Ранг: Форумен бог
Регистриран на: Пет Ное 12, 2004 3:38 pm Мнения: 9103 Местоположение: Chicago, IL
|
Ама много го задълбавате, я да си сложи човека switch и case-вете и да не се мъчи  .
|
| Сря Мар 23, 2005 8:45 pm |
|
 |
|
Nikola Kirov
Ранг: Форумен бог
Регистриран на: Нед Окт 31, 2004 9:19 pm Мнения: 4464 Местоположение: Stara Zagora
|
Аз наскоро писах подобно нещо.Имах над 70 функции. За да се работи прегледно и удобно ги разбих на 4 групи които са с отделен swich-case.
Правих програматор и се налагаше да гоня и бързина така че сравнявах бързодеиствие с друг вариант които бях направил с масив с указатели. Оказа се че резултатите са сходни. Просто варианта с swich-case е по лесен за настроиване и модификация
|
| Съб Мар 26, 2005 2:02 pm |
|
 |
|
Цецо
Ранг: Форумен бог
Регистриран на: Пон Сеп 27, 2004 9:22 am Мнения: 15501 Местоположение: София
|
Е не би трябвало резултата по бързодействие да е сходен. SWITCH - CASE минава през всички CASE-ове докато стигне до подходящия. Масива с указатели би трябвало да работи със сумиране+индексиране. Нещо по-важно времето за достъп до функцията при втория метод би трябвало да е константен докато при първия времето расте с номера на функцията. Така си мисля.
Ще експериментирам и двата варианта. Не съм сигурен че компилатора ми поддържа указатели към функция - не че е нещо сложно, ама за MPLAB C18 иде реч.
_________________ "Да еба и шибаната държава" мислеше си Гошо, докато се опитваше да улучи кофата за боклук от балкона на осмия етаж.
|
| Съб Мар 26, 2005 6:57 pm |
|
 |
|
Nikola Kirov
Ранг: Форумен бог
Регистриран на: Нед Окт 31, 2004 9:19 pm Мнения: 4464 Местоположение: Stara Zagora
|
Идеята с разбиването на групи е че първо проверяваш в кои блок е съответната функция и предаваш управлението в съответния swich-case.
Taka при мен се получи че максималното време за изпълнение беше незначително повече при този метод.Но затова пък по удобно.
|
| Съб Мар 26, 2005 9:01 pm |
|
 |
|
ToHu
Ранг: Форумен бог
Регистриран на: Нед Сеп 26, 2004 9:21 pm Мнения: 30684 Местоположение: София
|
Хммм не е точно така за switch-а .. компилатора си го оптимизира по самите стойности в switch и ако са типоследователни го изпълнява не с проверка на всички докато открие разлика, ами с указател.
|
| Съб Мар 26, 2005 9:52 pm |
|
 |
|
Nikola Kirov
Ранг: Форумен бог
Регистриран на: Нед Окт 31, 2004 9:19 pm Мнения: 4464 Местоположение: Stara Zagora
|
Виж за това не знам. Разбиването на групи го правих за мое удобство наи вече. А го правих за PC и не съм следил какво генерира компилатора. Просто засичах времената за изпълнение и се оказа че разликата е съвсем малка.
|
| Нед Мар 27, 2005 1:45 am |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
Масива от указатели има и друго предимство, а то е когато програмата се пише от колектив ( можеш да раздадеш на отделните програмисти кои функции да напишат ) , или пък когато за по лесното поддържане на софтуера е нужно отделните функции да са в различни файлове, по смислово съдържание, а пък и програмата е по прегледна с масива от функции. Бързодействието зависи от компилатора, процесора и дали case-вете са последователни числа ( ако са последователни числа, добрите компилатори реализират таблица с jmp към съответния case ). Най-добре е да се направи тестова програма, реализираща и двата варианта и да се види какво генерира компилатора. Обаче използваш ли масив, прави проверка за обхвата на индекса, защото никой C/C++ компилатор не се интересува дали извикваната функция има нулев(NULL) или различен от нула адрес ( в някои процесори на нулев адрес има системни подпрограми ) MCC18 компилатора поддържа указатели към функции.
|
| Нед Мар 27, 2005 2:14 am |
|
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 5 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|