Оператор switch — различия между версиями
Ulysses (обсуждение | вклад) м |
Ulysses (обсуждение | вклад) (добавлена цепочка if (если необходимы диапазоны), улучшено форматирование) |
||
(не показаны 2 промежуточные версии этого же участника) | |||
Строка 1: | Строка 1: | ||
Оператор выбора switch в C/C++ похож на оператор выбора case в Паскале. Например, выбор можно осуществлять по выражению «интегрального» типа (целые типы, символьный тип). Однако имеется, по меньшей мере, два важных отличия. Первое состоит в том, что в качестве меток используются только константы или константные выражения. То есть не могут, например, использоваться диапазоны, как в Паскале, нельзя также перечислять значения через запятую. Второе отличие — более тонкое, поясним его на примере. | Оператор выбора switch в C/C++ похож на оператор выбора case в Паскале. Например, выбор можно осуществлять по выражению «интегрального» типа (целые типы, символьный тип). Однако имеется, по меньшей мере, два важных отличия. Первое состоит в том, что в качестве меток используются только константы или константные выражения. То есть не могут, например, использоваться диапазоны, как в Паскале, нельзя также перечислять значения через запятую. Второе отличие — более тонкое, поясним его на примере. | ||
<source lang="Pascal">case i of | <source lang="Pascal">case i of | ||
− | 1 : f; | + | 1: f; |
− | 2 : g; | + | 2: g; |
− | else : h; | + | else: h; |
end; // case | end; // case | ||
</source> | </source> | ||
Если попытаться дословно перевести его на C, получится: | Если попытаться дословно перевести его на C, получится: | ||
<source lang="cpp">switch (i) { | <source lang="cpp">switch (i) { | ||
− | case 1 : f(); | + | case 1: f(); |
− | case 2 : g(); | + | case 2: g(); |
− | default : h(); | + | default: h(); |
− | } | + | } // switch |
</source> | </source> | ||
− | И это будет неверным. Например, в случае i = 1 будут вызваны все три функции f, g, h. Дело в том, что switch ищет первую константу, значение которой совпадает с i и просто передаёт управление в это место (к вызову f в случае i = 1). Далее весь код исполняется подряд. Если мы хотим добиться поведения, аналогичного Паскалю, необходимо использовать оператор break для принудительного выхода из тела switch. Правильный перевод на C исходного примера на Паскаль такой: | + | И это будет '''неверным'''. Например, в случае i = 1 будут вызваны все три функции f, g, h. Дело в том, что switch ищет первую константу, значение которой совпадает с i и просто передаёт управление в это место (к вызову f в случае i = 1). Далее весь код исполняется подряд. Если мы хотим добиться поведения, аналогичного Паскалю, необходимо использовать оператор break для принудительного выхода из тела switch. |
+ | |||
+ | '''Правильный перевод на C''' исходного примера на Паскаль такой: | ||
<source lang="cpp">switch (i) { | <source lang="cpp">switch (i) { | ||
− | case 1 : f(); break; | + | case 1: |
− | case 2 : g(); break; | + | f(); |
− | default : h(); | + | break; |
+ | case 2: | ||
+ | g(); | ||
+ | break; | ||
+ | default: | ||
+ | h(); | ||
} | } | ||
</source> | </source> | ||
+ | Стоит напомнить, что если в ветке case содержится оператор возврата из функции <tt>return</tt>, то ставить в ней <tt>break</tt> '''излишне'''. | ||
− | + | Используя описанную выше особенность поведения <tt>switch</tt>, можно смоделировать перечисление констант, как в Паскале: | |
− | Используя описанную особенность поведения switch, можно смоделировать перечисление констант, как в Паскале: | ||
<source lang="Pascal">case i of | <source lang="Pascal">case i of | ||
− | 1 : f; | + | 1: f; |
− | 2, 3 : g; | + | 2, 3: g; |
− | else | + | else h; |
end; // case | end; // case | ||
</source> | </source> | ||
эквивалентно: | эквивалентно: | ||
<source lang="cpp">switch (i) { | <source lang="cpp">switch (i) { | ||
− | case 1 : f(); break; | + | case 1: |
− | case 2 : case 3 : g(); break; | + | f(); |
− | default : h(); | + | break; |
+ | case 2: case 3: | ||
+ | g(); | ||
+ | break; | ||
+ | default: | ||
+ | h(); | ||
} | } | ||
</source> | </source> | ||
+ | |||
+ | Однако в C и C++ нет аналога выражений-диапазонов из Паскаля (например, <tt>6..15</tt>). Если требуется такая проверка принадлежности диапазону, то придётся писать десять <tt>case</tt> или заменить <tt>switch</tt> на обычную цепочку условных операторов: | ||
+ | <source lang="cpp">if (1 == i) { | ||
+ | f(); | ||
+ | } else if (2 == i || 3 == i) { | ||
+ | g(); | ||
+ | } else if (6 <= i && i <= 15) | ||
+ | h(); | ||
+ | } | ||
+ | </source> | ||
+ | В этом примере стоит обратить внимание на: | ||
+ | |||
+ | # Оформление конструкции <tt>else if</tt> (без перехода на новую строку и без дополнительных отступов), в этом случае её вид достаточно хорошо отражает смысл происходящего. | ||
+ | # Сравнение на равенство: <tt>3 == i</tt> вместо более привычного <tt>i == 3</tt> — так часто пишут, чтобы исключить возможность ошибки, когда вместо <tt>==</tt> используется <tt>=</tt>. | ||
+ | # Оформление двойного неравенства: в таком виде оно больше всего похоже на математическую запись. | ||
[[Категория:C++]] | [[Категория:C++]] |
Текущая версия на 11:22, 18 сентября 2014
Оператор выбора switch в C/C++ похож на оператор выбора case в Паскале. Например, выбор можно осуществлять по выражению «интегрального» типа (целые типы, символьный тип). Однако имеется, по меньшей мере, два важных отличия. Первое состоит в том, что в качестве меток используются только константы или константные выражения. То есть не могут, например, использоваться диапазоны, как в Паскале, нельзя также перечислять значения через запятую. Второе отличие — более тонкое, поясним его на примере.
case i of
1: f;
2: g;
else: h;
end; // case
Если попытаться дословно перевести его на C, получится:
switch (i) {
case 1: f();
case 2: g();
default: h();
} // switch
И это будет неверным. Например, в случае i = 1 будут вызваны все три функции f, g, h. Дело в том, что switch ищет первую константу, значение которой совпадает с i и просто передаёт управление в это место (к вызову f в случае i = 1). Далее весь код исполняется подряд. Если мы хотим добиться поведения, аналогичного Паскалю, необходимо использовать оператор break для принудительного выхода из тела switch.
Правильный перевод на C исходного примера на Паскаль такой:
switch (i) {
case 1:
f();
break;
case 2:
g();
break;
default:
h();
}
Стоит напомнить, что если в ветке case содержится оператор возврата из функции return, то ставить в ней break излишне.
Используя описанную выше особенность поведения switch, можно смоделировать перечисление констант, как в Паскале:
case i of
1: f;
2, 3: g;
else h;
end; // case
эквивалентно:
switch (i) {
case 1:
f();
break;
case 2: case 3:
g();
break;
default:
h();
}
Однако в C и C++ нет аналога выражений-диапазонов из Паскаля (например, 6..15). Если требуется такая проверка принадлежности диапазону, то придётся писать десять case или заменить switch на обычную цепочку условных операторов:
if (1 == i) {
f();
} else if (2 == i || 3 == i) {
g();
} else if (6 <= i && i <= 15)
h();
}
В этом примере стоит обратить внимание на:
- Оформление конструкции else if (без перехода на новую строку и без дополнительных отступов), в этом случае её вид достаточно хорошо отражает смысл происходящего.
- Сравнение на равенство: 3 == i вместо более привычного i == 3 — так часто пишут, чтобы исключить возможность ошибки, когда вместо == используется =.
- Оформление двойного неравенства: в таком виде оно больше всего похоже на математическую запись.