Considere a seguinte switch
declaração:
switch( value )
{
case 1:
return 1;
default:
value++;
// fall-through
case 2:
return value * 2;
}
Esse código é compilado, mas é válido (= comportamento definido) para C90 / C99? Nunca vi código em que o caso padrão não seja o último.
Edição:
Como Jon Cage e KillianDS escrevem: este é um código realmente feio e confuso e eu estou ciente disso. Estou interessado apenas na sintaxe geral (está definida?) E na saída esperada.
c
switch-statement
tanascius
fonte
fonte
goto
não é mau. Seguidores de culto de carga são! Você não pode imaginar até que ponto as pessoas extremos podem evitar,goto
porque é supostamente tão ruim, criando uma verdadeira bagunça ilegível de seu código.goto
principalmente para simular algo como umafinally
cláusula em funções, em que recursos (arquivos, memória) precisam ser liberados ao parar e repetir para cada caso de erro uma listafree
eclose
não ajuda na legibilidade. Há um usogoto
que eu gostaria de evitar, mas não posso, é quando eu quero sair de um loop e estou dentro de umswitch
loop.Respostas:
O padrão C99 não é explícito sobre isso, mas, considerando todos os fatos, é perfeitamente válido.
A
case
edefault
label são equivalentes a umgoto
rótulo. Consulte 6.8.1 Instruções rotuladas. Especialmente interessante é o 6.8.1.4, que permite o já mencionado dispositivo de Duff:Edit : O código dentro de um switch não é nada de especial; é um bloco de código normal como em uma
if
declaração, com rótulos de salto adicionais. Isso explica o comportamento direto e por quebreak
é necessário.6.8.4.2.7 até dá um exemplo:
As constantes de caso devem ser exclusivas em uma instrução switch:
Todos os casos são avaliados e, em seguida, passam para o rótulo padrão, se fornecido:
fonte
default
caso que domina outros casos em cerca de 100: 1 e não sei se é válido ou indefinido fazerdefault
o primeiro caso.As instruções de caso e a instrução padrão podem ocorrer em qualquer ordem na instrução switch. A cláusula padrão é uma cláusula opcional que corresponde se nenhuma das constantes nas instruções de caso puder ser correspondida.
Bom exemplo :-
muito útil se você deseja que seus casos sejam apresentados em uma ordem lógica no código (como em não dizer caso 1, caso 3, caso 2 / padrão) e seus casos são muito longos, portanto, você não deseja repetir o caso inteiro código na parte inferior para o padrão
fonte
É válido e muito útil em alguns casos.
Considere o seguinte código:
O ponto é que o código acima é mais legível e eficiente do que em cascata
if
. Você pode colocardefault
no final, mas é inútil, pois concentrará sua atenção em casos de erro em vez de casos normais (que é odefault
caso aqui ).Na verdade, não é um exemplo tão bom, pois
poll
você sabe quantos eventos podem ocorrer no máximo. Meu verdadeiro ponto é que não são casos com um conjunto definido de valores de entrada, onde há 'exceções' e casos normais. Se é melhor colocar exceções ou casos normais na frente, é uma questão de escolha.No campo do software, penso em outro caso muito comum: recursões com alguns valores terminais. Se você pode expressá-lo usando um comutador,
default
será o valor usual que contém chamada recursiva e elementos distintos (casos individuais) dos valores do terminal. Geralmente, não há necessidade de se concentrar nos valores dos terminais.Outro motivo é que a ordem dos casos pode alterar o comportamento do código compilado, e isso é importante para as performances. A maioria dos compiladores gerará código de montagem compilado na mesma ordem em que o código aparece no comutador. Isso torna o primeiro caso muito diferente dos outros: todos os casos, exceto o primeiro, envolvem um salto e esvaziam os pipelines do processador. Você pode entendê-lo como preditor de ramificação por padrão para executar o primeiro caso que aparece no comutador. Se um caso é muito mais comum que os outros, você tem boas razões para colocá-lo como o primeiro caso.
A leitura dos comentários é a razão específica pela qual o pôster original fez essa pergunta depois de ler a reorganização do Branch Loop do compilador Intel sobre otimização de código.
Então se tornará uma arbitragem entre a legibilidade e o desempenho do código. Provavelmente é melhor colocar um comentário para explicar ao futuro leitor por que um caso aparece primeiro.
fonte
case
. O que é deprimente é que parece com açúcar sintático e não quebra nenhum código existente, se suportado.Sim, isso é válido e, em algumas circunstâncias, é útil. Geralmente, se você não precisar, não faça.
fonte
Não há ordem definida em uma instrução switch. Você pode considerar os casos como algo como um rótulo nomeado, como um
goto
rótulo. Ao contrário do que as pessoas parecem pensar aqui, no caso do valor 2 o rótulo padrão não é utilizado. Para ilustrar com um exemplo clássico, aqui está o dispositivo de Duff , que é o filho dos extremos deswitch/case
C.fonte
Um cenário em que eu consideraria apropriado ter um 'padrão' localizado em algum lugar que não seja o final de uma instrução de caso está em uma máquina de estado em que um estado inválido deve redefinir a máquina e continuar como se fosse o estado inicial. Por exemplo:
um arranjo alternativo, se um estado inválido não deve reiniciar a máquina, mas deve ser facilmente identificável como um estado inválido:
O código em outro local pode então procurar por (widget_state == WIDGET_INVALID_STATE) e fornecer qualquer comportamento de relatório de erros ou redefinição de estado que pareça apropriado. Por exemplo, o código da barra de status pode mostrar um ícone de erro e a opção de menu "Iniciar widget", que está desativada na maioria dos estados não ociosos, pode ser ativada para WIDGET_INVALID_STATE e WIDGET_IDLE.
fonte
Discutindo com outro exemplo: Isso pode ser útil se "padrão" for um caso inesperado e você desejar registrar o erro, mas também fazer algo sensato. Exemplo de alguns dos meus próprios códigos:
fonte
Há casos em que você está convertendo ENUM em uma string ou convertendo em enum no caso de estar gravando / lendo em / de um arquivo.
Às vezes, você precisa tornar um dos valores padrão para cobrir erros cometidos pela edição manual de arquivos.
fonte
A
default
condição pode estar em qualquer lugar dentro do comutador em que uma cláusula de caso possa existir. Não é necessário que seja a última cláusula. Eu vi o código que coloca o padrão como a primeira cláusula. Ocase 2:
é executado normalmente, mesmo que a cláusula padrão esteja acima dele.Como teste, coloquei o código de exemplo em uma função, chamada
test(int value){}
e executada:A saída é:
fonte
É válido, mas bastante desagradável. Eu sugeriria que geralmente é ruim permitir falhas, pois isso pode levar a um código de espaguete muito confuso.
É quase certamente melhor dividir esses casos em várias instruções de chave ou em funções menores.
[edit] @Tristopia: Seu exemplo:
seria mais claro quanto à sua intenção (eu acho) se fosse escrito assim:
[edit2] @Tristopia: Seu segundo exemplo é provavelmente o exemplo mais limpo de um bom uso para acompanhamento:
..mas pessoalmente eu dividiria o reconhecimento de comentários em sua própria função:
fonte
r
é a matriz de destino,wc
é owchar_t
comutador de entrada (utf8_length) {/ * Nota: o código ocorre entre os casos! * / caso 3: r [2] = 0x80 | (wc & 0x3f); wc >> = 6; wc | = 0x800; caso 2: r [1] = 0x80 | (wc & 0x3f); wc >> = 6; wc | = 0xc0; caso 1: r [0] = wc; }for(i=0; s[i]; i++) { switch(s[i]) { case '"': case '\'': case '\\': d[dlen++] = '\\'; /* fall through */ default: d[dlen++] = s[i]; } }