Есть блок однотипных условий вида. Всего условий около 120.
if (event_code == 0xF1)
{
// action 1
}
else if (event_code == 0xEF)
{
// action 2
}
...
else if (event_code == 0xDB)
{
// action 119
}
else
{
// print event_code
}
Проблема в условии 119 (event_code == 0xDB). Если в коде разместить это условие в самом конце, то оно не выполняется, а вместо него выполняется условие else, которое выводит на печать event_code = 0xDB
. Все касты и приведения типов в порядке, т.к. если разместить данное условие в начале блока, то оно начинает работать...
Пробовал переделать блок на switch-case и получил такой же результат. Собирается проект с помощью icc 14.0.2.176 [IA-32]. В доках на icc никаких ограничений не нашел.
Помогите кто чем может)
Покажу несколько способов оптимизации условий.
Метод двоичного поиска. Мы выстраиваем дерево таким образом, что бы колличество сравнений было минимальное (обратите внимание что б event_code был unsigned)
if (event_code <= 0xEF) { /*Уровень 1*/
if (event_code == 0xDB) {/*Уровень 2*/
}
if (event_code == 0xEE) {/*Уровень 2*/
}
}else { /*Уровень 1*/
if (event_code == 0xEF) {/*Уровень 2*/
}
if (event_code == 0xF1)/*Уровень 2*/
{
// action 1
}
}
это было дерево {{ EE,EF } , {0xEF, F1 }} На этом примере не так хорошо видно ефект дерева. Вот пример, как вычислить число бит нужных для числа то 0 до 255
if (a<16){/*1*/
if (a<4){/*2*/
if (a<=1)/*3*/ return 1 else return 2;
}else{/*2*/
if (a<8)/*3*/ return 3 else return 4;
}
}else{/*1*/
if (a < 64)/*2*/ {
if (a < 32)/*3*/ return 5; else return 6;
} else {
if (a < 128)/*3*/ return 7; else return 8;
}
Тут за три сравнения ясен результат. Три, не 8, не 256. Так можно успешно оптимизировать число сравнений.
Метод switch. Многие компиляторы хорошо оптимизируют выражение в switch. Думаю вы ничего не потеряете если используете switch. Одни компиляторы стоят "дерево" как показано в [1], другие строят таблицу вызовов как в [3]. Но и бывают случаи когда просто лепят сравнения. Проверить что сгенерировал компилятор можно дизассемблером.
switch ((unsigned)event_code) {
case 0xDB:; break;
case 0xEF:; break;
case 0xF1:; break;
//...
}
Я часто пользовался switch, и... иногда нужно "выйти" из него не вниз, а вообще. Поэтому кроме break, есть ещё два способа "остановить процесс сравнения" - это return
и continue
(если используется цикл).
Метод массива вызовов.
void handler_1() {
}
void (*my_handlers[])() = { NULL, NULL /*... */, handler_1 };
void my_proc() {
if (my_handlers[(unsigned)event_code] != NULL)
my_handlers[(unsigned)event_code]();
}
этот метод ефективен если случаев очень много, и они сфокусированы на большом промежутке чисел, например от 0 до 255.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок