Por meio de um pequeno erro de digitação, encontrei acidentalmente esse construto:
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;
}
Parece que a printf
parte superior da switch
declaração é válida, mas também completamente inacessível.
Eu obtive uma compilação limpa, sem sequer um aviso sobre código inacessível, mas isso parece inútil.
Um compilador deve sinalizar isso como código inacessível?
Isso serve a algum propósito?
c
switch-statement
language-lawyer
abelenky
fonte
fonte
-Wswitch-unreachable
goto
entrar e sair da parte inacessível, que pode ser útil para vários hacks.switch
é apenas uma condiçãogoto
com vários rótulos. Existem mais ou menos as mesmas restrições em seu corpo que você teria em um bloco de código regular preenchido com rótulos de goto.Respostas:
Talvez não seja o mais útil, mas não completamente inútil. Você pode usá-lo para declarar uma variável local disponível no
switch
escopo.O padrão (
N1579 6.8.4.2/7
) tem o seguinte exemplo:PS BTW, a amostra não é um código C ++ válido. Nesse caso (
N4140 6.7/3
ênfase minha):Portanto, substituir
int i = 4;
porint i;
torna um C ++ válido.fonte
i
foi inicializado com 4, o que estou perdendo?static
, ela será inicializada como zero, portanto, há um uso seguro para isso também.i = 4;
inicialização, para que nunca ocorra.case
e sempre precisava usar nomes diferentes em cada umacase
ou defini-la fora do comutador.Sim. Se, em vez de uma declaração, você colocar uma declaração antes do primeiro rótulo, isso pode fazer todo o sentido:
As regras para declarações e declarações são compartilhadas para blocos em geral, portanto, é a mesma regra que permite que isso também permita declarações lá.
Também vale a pena mencionar que, se a primeira instrução for uma construção de loop, os rótulos de caso poderão aparecer no corpo do loop:
Por favor, não escreva um código como este se houver uma maneira mais legível de escrevê-lo, mas é perfeitamente válido e a
f()
chamada é acessível.fonte
{ /*code*/ switch(x) { } }
pode parecer mais limpo, mas também está errado .Existe um uso famoso desse dispositivo chamado Duff's Device .
Aqui, copiamos um buffer apontado por por
from
para um buffer apontado porto
. Copiamoscount
instâncias de dados.A
do{}while()
instrução começa antes do primeirocase
rótulo e oscase
rótulos são incorporados nodo{}while()
.Isso reduz o número de ramificações condicionais no final do
do{}while()
loop encontrado por aproximadamente um fator de 4 (neste exemplo; a constante pode ser ajustada para qualquer valor que você desejar).Agora, às vezes, os otimizadores podem fazer isso por você (especialmente se estão otimizando instruções de streaming / vetorizadas), mas sem a otimização guiada por perfil, eles não sabem se você espera que o loop seja grande ou não.
Em geral, as declarações de variáveis podem ocorrer lá e ser usadas em todos os casos, mas ficam fora do escopo após o término da opção. (observe que qualquer inicialização será ignorada)
Além disso, o fluxo de controle que não é específico do comutador pode levá-lo àquela seção do bloco do comutador, conforme ilustrado acima, ou com a
goto
.fonte
do {
e o valorcase 0:
não importam servem para colocar um alvo de salto no primeiro*to = *from++;
.do {
é mais legível. Sim, argumentar sobre a legibilidade do dispositivo de Duff é estúpido e inútil e provavelmente uma maneira simples de enlouquecer.Supondo que você esteja usando o gcc no Linux, isso seria um aviso se você estivesse usando a versão 4.4 ou anterior.
A opção -Wunreachable-code foi removida no gcc 4.4 em diante.
fonte
Não apenas para declaração de variáveis, mas também para salto avançado. Você pode utilizá-lo bem se, e somente se, não for propenso ao código de espaguete.
Impressões
Deve-se notar que a caixa de comutação é uma das cláusulas de fluxo de controle mais rápidas. Portanto, deve ser muito flexível para o programador, o que às vezes envolve casos como este.
fonte
nocase:
edefault:
?i=4
não disparanocase
.Deve-se observar que praticamente não há restrições estruturais no código da
switch
instrução ou em onde oscase *:
rótulos são colocados nesse código *. Isso possibilita truques de programação como o dispositivo de duff , uma implementação possível da seguinte forma:Veja bem, o código entre o
switch(n%8) {
e ocase 7:
rótulo é definitivamente acessível ...* Como supercat apontou felizmente em um comentário : Desde C99, nem um
goto
nem um rótulo (seja umcase *:
rótulo ou não) podem aparecer no escopo de uma declaração que contenha uma declaração VLA. Portanto, não é correto dizer que não há restrições estruturais na colocação dascase *:
etiquetas. No entanto, o dispositivo da duff é anterior ao padrão C99 e, de qualquer maneira, não depende dos VLAs. No entanto, senti-me compelido a inserir um "virtualmente" na minha primeira frase devido a isso.fonte
goto
nemswitch/case/default
pode aparecer no escopo de qualquer objeto ou tipo declarado de forma variável. Isso significa efetivamente que, se um bloco contiver declarações de objetos ou tipos de array de comprimento variável, quaisquer rótulos deverão preceder essas declarações. Há um pouco de verborragia confusa no Padrão, o que sugere que, em alguns casos, o escopo de uma declaração VLA se estende a toda a declaração de switch; veja stackoverflow.com/questions/41752072/… para minha pergunta sobre isso.Você tem sua resposta relacionada com o exigido
gcc
opção-Wswitch-unreachable
para gerar o aviso, esta resposta é para a reflexão sobre a usabilidade / worthyness parte.Citando diretamente o
C11
capítulo §6.8.4.2, ( grifo meu )O que é muito auto-explicativo. Você pode usar isso para definir uma variável com escopo local que está disponível apenas dentro do
switch
escopo da instrução.fonte
É possível implementar um "loop e meio" com ele, embora possa não ser a melhor maneira de fazê-lo:
fonte