Через небольшую опечатку я случайно нашел эту конструкцию:
int main(void) {
char foo = 'c';
switch(foo)
{
printf("Cant Touch This\n"); // This line is Unreachable
case 'a': printf("A\n"); break;
case 'b': printf("B\n"); break;
case 'c': printf("C\n"); break;
case 'd': printf("D\n"); break;
}
return 0;
}
Кажется, что printf
в верхней части switch
утверждения является действительным, но также совершенно недоступным.
Я получил чистую компиляцию, даже без предупреждения о недоступном коде, но это кажется бессмысленным.
Должен ли компилятор пометить это как недоступный код?
Это вообще служит какой-либо цели?
c
switch-statement
language-lawyer
abelenky
источник
источник
-Wswitch-unreachable
goto
входить и выходить из недоступной части, которая может быть полезна для различных взломов.switch
это просто условиеgoto
с несколькими метками. Его тело имеет более или менее те же ограничения, что и обычный блок кода, заполненный метками goto.Ответы:
Возможно, не самый полезный, но не совсем бесполезный. Вы можете использовать его для объявления локальной переменной, доступной в
switch
области видимости.Стандарт (
N1579 6.8.4.2/7
) имеет следующий образец:PS Кстати, образец не является допустимым кодом C ++. В этом случае (
N4140 6.7/3
выделите мое):Таким образом, замена
int i = 4;
наint i;
делает его действительным C ++.источник
i
инициализируется до 4, что я пропускаю?static
, она будет инициализирована нулем, так что для этого также есть безопасное использование.i = 4;
инициализацию, поэтому она никогда не происходит.case
, и мне всегда приходилось использовать разные имена в каждомcase
или определять ее вне переключателя.Да. Если вместо утверждения вы поместите объявление перед первым ярлыком, это может иметь смысл:
Правила для объявлений и операторов являются общими для блоков в целом, так что это то же правило, которое допускает это, что также позволяет использовать операторы там.
Стоит также упомянуть, что если первый оператор является конструкцией цикла, в теле цикла могут появляться метки case:
Пожалуйста, не пишите код, подобный этому, если есть более читаемый способ его написания, но он совершенно действителен и
f()
вызов доступен.источник
{ /*code*/ switch(x) { } }
может выглядеть чище, но это также неправильно .Есть известное использование этого устройства под названием Duff's .
Здесь мы копируем буфер, на который указывает,
from
в буфер, на который указываетto
. Мы копируемcount
экземпляры данных.do{}while()
Заявление начинается перед первойcase
этикеткой, аcase
метки встроены внутриdo{}while()
.Это уменьшает количество условных переходов в конце
do{}while()
цикла, встречающихся примерно в 4 раза (в этом примере константу можно настроить на любое значение, которое вы хотите).Теперь оптимизаторы могут иногда делать это для вас (особенно, если они оптимизируют потоковые / векторизованные инструкции), но без оптимизации по профилю они не могут знать, ожидаете ли вы большой цикл или нет.
В общем, объявления переменных могут встречаться там и использоваться в каждом случае, но выходить за рамки после завершения переключения. (обратите внимание, что любая инициализация будет пропущена)
Кроме того, поток управления, не зависящий от переключателя, может привести вас в этот раздел блока переключателей, как показано выше, или с помощью a
goto
.источник
do {
иcase 0:
не имеет значения, оба служат для размещения цели перехода в первом*to = *from++;
.do {
более читабельно. Да, спорить о читабельности устройства Даффа глупо и бессмысленно, и, вероятно, это простой способ сойти с ума.Если вы используете gcc в Linux, вы получите предупреждение, если вы используете 4.4 или более раннюю версию.
Опция -Wunreachable-code была удалена в gcc 4.4 и более поздних версиях .
источник
Не только для объявления переменных, но и для сложных прыжков. Вы можете использовать его хорошо, если и только если вы не склонны к спагетти-коду.
Печать
Следует отметить, что распределительный шкаф является одним из самых быстрых условий потока управления. Так что он должен быть очень гибким для программиста, что иногда включает в себя такие случаи.
источник
nocase:
аdefault:
?i=4
он не срабатываетnocase
.Следует отметить, что практически нет структурных ограничений на код внутри
switch
оператора или на то, гдеcase *:
в этом коде размещены метки *. Это делает возможными трюки программирования, такие как устройство Даффа, одна из возможных реализаций которого выглядит следующим образом:Видите ли, код между
switch(n%8) {
иcase 7:
меткой определенно доступен ...* Как Supercat благодарно отметил в комментарии : Так как C99, ни ,
goto
ни ярлык (будь этоcase *:
метка или нет) не могут появляться в рамках декларации, которая содержит декларацию VLA. Поэтому неправильно говорить, что нет никаких структурных ограничений на размещениеcase *:
этикеток. Однако устройство Даффа предшествует стандарту C99, и оно все равно не зависит от VLA. Тем не менее, я чувствовал себя обязанным вставить «виртуально» в мое первое предложение из-за этого.источник
goto
ниswitch/case/default
метка не могут появляться в области действия любого объекта или типа с переменной декларацией. Это фактически означает, что если блок содержит какие-либо объявления объектов или типов массива переменной длины, любые объявления должны предшествовать этим объявлениям. В Стандарте есть немного запутанного словоблудия, которое предполагает, что в некоторых случаях область действия декларации VLA распространяется на весь оператор switch; см. stackoverflow.com/questions/41752072/… мой вопрос по этому вопросу.Вы получили свой ответ, связанный с необходимой
gcc
опцией-Wswitch-unreachable
для генерации предупреждения, этот ответ предназначен для более подробной информации о юзабилити / достоинстве .Цитировать прямо из
C11
главы §6.8.4.2 ( выделено мной )Что очень очевидно. Вы можете использовать это, чтобы определить локальную переменную, которая доступна только в пределах
switch
оператора.источник
Можно реализовать «цикл с половиной» с ним, хотя это может быть не лучшим способом сделать это:
источник