Переключатель регистра работает так?
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:
линию, разве она не проверяет, соответствует ли ваше текущее значение конкретному случаю, и только затем позволяет вам войти в определенный сегмент? Иначе какой смысл иметь дело?
Ответы (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
, оно покидает блок переключателей.
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:062 плюса
К счастью для нас, C ++ не зависит от вашего воображения :-)
Думайте о метках переключателей как о метках «goto», а switch(blah)
просто «идет» к соответствующей метке, и тогда код просто вытекает оттуда.
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
случаев идентичен, за исключением расчета размера в случае строки.
Вопросы из категории :
- c++ What are the barriers to understanding pointers and what can be done to overcome them?
- c++ Какой самый простой способ для анализа файла INI в C ++?
- c++ Когда вы должны использовать «друг» в C ++?
- c++ Как вы очищаете переменную stringstream?
- c++ В C ++ конструктор и деструктор могут быть встроенными функциями?
- c++ Что такое виртуальный базовый класс в C ++?
- c++ В чем разница между #include <filename> и #include "filename"?
- c++ Какой самый лучший бесплатный детектор утечки памяти для программы на C / C ++ и ее подключаемых библиотек DLL?
- c++ Как преобразовать std :: string в LPCWSTR в C ++ (Unicode)
- c++ Regular cast vs. static_cast vs. dynamic_cast
- c Как вы форматируете unsigned long long int, используя printf?
- c Как реализовать продолжения?
- c Как вы передаете функцию в качестве параметра в C?
- c Как получить список каталогов в C?
- c Всегда ли выгодно использовать «goto» в языке, который поддерживает циклы и функции? Если так, то почему?
- c В чем разница между ++ i и i ++?
- c Есть ли разница в производительности между i ++ и ++ i в C?