Получение количества случаев в switch-case в C

Можно ли получить количество случаев в случае переключения в C без ручного добавления переменной-счетчика, которая увеличивается в каждом случае?


person floquet22    schedule 10.02.2016    source источник
comment
Вы имеете в виду подсчет количества операторов case, которые вы написали или сгенерировали в макросе? Я не думаю, что вы могли бы использовать счетчик для этого - они не будут выполняться, если вы не пройдете каждый путь кода. Интересно, для чего вам это нужно?   -  person Rup    schedule 10.02.2016
comment
Я бы сказал, что короткий ответ: нет, вы не можете. Однако мне кажется, что вашу проблему лучше решить с помощью таблицы диспетчеризации, а не оператора switch. (По крайней мере, подумайте об этом.)   -  person Øystein Schønning-Johansen    schedule 10.02.2016
comment
Возможно, ваш вопрос связан с проблемой XY. Чего вы действительно пытаетесь достичь?   -  person kaylum    schedule 10.02.2016
comment
уродливые футляры без break?   -  person Peter Miehle    schedule 10.02.2016
comment
@PeterMiehle, это тоже пришло мне в голову, но я слишком боялся опубликовать это :)   -  person Martin James    schedule 10.02.2016
comment
Это можно легко сделать, если каждое значение case берется из перечисления, где все значения являются смежными, и ВСЕ они используются в блоке switch. Но вообще такие вещи обычно не полезно знать. Вы используете перечисление таким образом?   -  person    schedule 10.02.2016
comment
конечно, счетчик, увеличиваемый в каждом случае, был ерундой.   -  person floquet22    schedule 10.02.2016
comment
Пожалуйста, отредактируйте свой вопрос, чтобы мотивировать его и точно объяснить, почему вы задаете этот вопрос. Похоже на проблему XY.   -  person Basile Starynkevitch    schedule 04.03.2016


Ответы (3)


Как я уже говорил ранее, я думаю, вам нужна таблица диспетчеризации, а не оператор switch. Вот небольшой пример.

Скажите, что вы получили это:

int find_the_case();
void do_something();
void do_something_different();
void do_something_completly_different();
void do_default();

int main(int argc, char *argv[])
{
    int c = find_the_case();
    switch(c){
        case 0:
           do_something();
           break;
        case 1:
           do_something_different();
           break;
        case 5:
           do_something_completly_different();
           break;
        default:
           do_default();
           break;
    }
    return 0;
}

Теперь это можно переписать следующим образом:

#define MAX_NUMBER_OF_CASES 6
int main_dispatchtable()
{
    void (*table[MAX_NUMBER_OF_CASES])(void)  = {
            [0] = do_something,
            [1] = do_something_different,
            [5] = do_something_completly_different
    };

    int c = find_the_case();
    if( table[c] )
            table[c]();
    else
            do_default();

    /* for the counting */
    int count = 0;
    for (int i = 0; i < MAX_NUMBER_OF_CASES; i++ )
            if( table[i] ) count++;

    return 0;
}

Обычно это намного лучше, чем использование операторов switch. Это не только упрощает добавление дополнительных случаев, но также позволяет подсчитывать случаи. Если у вас есть огромная таблица и редкие случаи, вы можете использовать хеш-таблицу вместо простого массива.

РЕДАКТИРОВАТЬ: Конечно, у таблицы диспетчеризации есть еще больше преимуществ, чем у переключателя, поскольку вы можете динамически добавлять, удалять и изменять таблицу диспетчеризации. Это может быть самым большим преимуществом.

person Øystein Schønning-Johansen    schedule 10.02.2016
comment
Обратите внимание, что на некоторых процессорах таблица диспетчеризации с непрямыми вызовами функций может работать довольно медленно. вычисленные переходы могут быть быстрее. См. мой ответ. - person Basile Starynkevitch; 04.03.2016

Это ужасно, но если вы используете gcc, вы можете использовать макрос COUNTER:

#include <stdio.h>

#define ncase (void)__COUNTER__; case

int main(void)
{
    int n = __COUNTER__ + 1;

    switch (1 + 1) {
        ncase 0: break;
        ncase 1: break;
        ncase 2: break;
    }
    n = __COUNTER__ - n;
    printf("%d cases\n", n);
    return 0;
}

Выход:

3 cases
person David Ranieri    schedule 10.02.2016
comment
был es nicht alles gibt! - person Peter Miehle; 10.02.2016

(Надеюсь, вы работаете в Linux и используете последний компилятор GCC )

Если вы хотите подсчитать фактическое количество наблюдений, которое видит компилятор (подумайте о диапазоны регистра), вам нужно знать внутренние представления компилятора, и вы могли бы, если компилируете с недавним GCC, настройте свой компилятор с помощью GCC MELT и создайте свой собственный MELT расширение.

Кстати, сложность или эффективность оператора switch связана не только (или в основном) с количеством случаев (поскольку распределение случаев имеет большое значение). См. ссылки здесь.

Возможно, вы могли бы просто использовать режим findgimple для GCC MELT, чтобы найти switch операторов gimple, которые достаточно широки.

Возможно, вам нужны вычисленные переходы для поточный код...

person Basile Starynkevitch    schedule 04.03.2016