Переключатель регистра работает так?

c++ c

11051 просмотра

5 ответа

Сегодня я натолкнулся на фрагмент кода с переключением регистра и был немного удивлен, увидев, как он работает. Код был:

switch (blah)
{
case a:
  break;
case b:
  break;
case c:
case d:
case e: 
  {
    /* code here */
  }
  break;
default :
  return;
}

К моему удивлению в сценарии, где была переменная c, путь шел внутри сегмента «здесь код». Я согласен, что в конце cчасти переключателя кейса нет перерывов , но я бы подумал, что это пройдет default. Когда вы приземляетесь на case blah:линию, разве она не проверяет, соответствует ли ваше текущее значение конкретному случаю, и только затем позволяет вам войти в определенный сегмент? Иначе какой смысл иметь дело?

Автор: Manish Источник Размещён: 12.11.2019 09:22

Ответы (5)


15 плюса

Решение

Это называется падением случая и является желательным поведением. Это позволяет вам делиться кодом между делами.

Пример использования падежного поведения:

switch(blah)
{
case a:
  function1();
case b:
  function2();
case c:
  function3();
  break;
default:
  break;
}

Если ввести переключатель , когда blah == a, то вы будете выполнять function1(), function2()и function3().

Если вы не хотите иметь такое поведение, вы можете отказаться от него, включив breakзаявления.

switch(blah)
{
case a:
  function1();
  break;
case b:
  function2();
  break;
case c:
  function3();
  break;
default:
  break;
}

Оператор switch работает так, что он (более или менее) выполняет a gotoдля перехода к метке вашего случая и продолжает работать с этой точки. Когда выполнение достигает a break, оно покидает блок переключателей.

Автор: Merlyn Morgan-Graham Размещён: 16.11.2011 02:59

10 плюса

Это правильное поведение, и оно называется «проваливается». Это позволяет обрабатывать несколько дел одним и тем же кодом. В сложных ситуациях может потребоваться выполнить некоторый код в одном случае, а затем перейти к другому.

Придуманный пример:

switch(command)
{
   case CMD_SAVEAS:
   {
      this->PromptForFilename();
   } // DO NOT BREAK, we still want to save
   case CMD_SAVE:
   {
      this->Save();
   } break;


   case CMD_CLOSE:
   {
      this->Close();
   } break;

   default:
      break;
}
Автор: shenles Размещён: 16.11.2011 02:59

4 плюса

Это называется провалом.

Это именно то, что вы видите: несколько случаев будут выполнять один и тот же кусок кода.

Также удобно выполнять дополнительную обработку для определенного случая и некоторую общую логику:

// psuedo code:
void stopServer() {
    switch (serverStatus)
    case STARTING:
    {
        extraCleanUpForStartingServer();
        // fall-thru
    }
    case STARTED:
    {
        deallocateResources();
        serverStatus = STOPPED;
        break;
    }
    case STOPPING:
    case STOPPED:
    default:
        // ignored
        break;
}

Это типичное использование провала в распределительном шкафу. В случае STARTING и STARTED нам нужно сделать deallocateResources и изменить статус на STOPPED, но для STARTING требуется дополнительная очистка. Таким образом, вы можете четко представить «общую логику» плюс дополнительную логику в ЗАПУСКЕ.

STOPPED, STOPPING и default одинаковы, все они относятся к логике по умолчанию (которая игнорируется).

Это не всегда хороший способ кодировать, как это, но если он хорошо используется, он может лучше представить логику.

Автор: Adrian Shum Размещён: 16.11.2011 03:06

2 плюса

К счастью для нас, C ++ не зависит от вашего воображения :-)

Думайте о метках переключателей как о метках «goto», а switch(blah)просто «идет» к соответствующей метке, и тогда код просто вытекает оттуда.

Автор: Kerrek SB Размещён: 16.11.2011 03:00

2 плюса

На самом деле оператор switch работает так, как вы заметили. Он спроектирован так, что вы можете объединить несколько случаев, пока не встретится разрыв, и он действует как сито.

Вот реальный пример из одного из моих проектов:

struct keystore_entry *new_keystore(p_rsd_t rsd, enum keystore_entry_type type, const void *value, size_t size) {
        struct keystore_entry *e;
        e = rsd_malloc(rsd, sizeof(struct keystore_entry));
        if ( !e ) 
                return NULL;
        e->type = type;
        switch (e->type) {
        case KE_DOUBLE:
                memcpy(&e->dblval, value, sizeof(double));
                break;
        case KE_INTEGER:
                memcpy(&e->intval, value, sizeof(int));
                break;

        /* NOTICE HERE */

        case KE_STRING:
                if ( size == 0 ) { 
                        /* calculate the size if it's zero */
                        size = strlen((const char *)value);
                }
        case KE_VOIDPTR:
                e->ptr = rsd_malloc(rsd, size);
                e->size = size;
                memcpy(e->ptr, value, size);
                break;

        /* TO HERE */
        default:
                return NULL;
        }
        return e;
}

Код для KE_STRINGи KE_VOIDPTRслучаев идентичен, за исключением расчета размера в случае строки.

Автор: Ahmed Masud Размещён: 16.11.2011 03:06
Вопросы из категории :
32x32