A fim de verificar as condições em C

0

Pergunta

Então, eu estava lendo sobre a ordem dos diferentes operadores, e eu li que && tem maior importância do que || e seria avaliar mais cedo (fonte). Em seguida, alguém fez uma pergunta sobre o que este pedaço de código deve imprimir:

#include <stdio.h>
int main(){
    int a=0, b=0, c=0, d=0;
    if(a++>0 || ++b==1 || c--<=0 && d++>c--){
        printf("if\na:%d\nb:%d\nc:%d\nd:%d\n",a,b,c,d);
    }
    else{
        printf("else\na:%d\nb:%d\nc:%d\nd:%d\n",a,b,c,d);
    }
    return 0;
}

E eu pensei que o c-- <= 0 && d++ > c-- gostaria de, primeiramente, avaliar, o que é verdade no total. após o processo, c seria igual a -2 e d seria igual a 1. Em seguida, ele iria começar a verificar a partir do lado esquerdo, a avaliação de a++ > 0 || ++b == 1 o que é verdade, a seria 1 no final e b é de 1 em a condição e o depois. assim, o total condição seria true || true e é verdade, por isso temos de impressão:

if
a:1
b:1
c:-2
d:1

Sim? Aparentemente, não. Eu testei com o GCC (Mingw) no meu sistema (Windows 10), e com uma linha de compilador (este) e impressas:

if
a:1
b:1
c:0
d:0

Eu mudei a condição para isso: if(a++>0 || ++b==1 || (c--<=0 && d++>c--) ) mas o resultado é exatamente o mesmo em ambos os lugares. Há algo que eu não prestar atenção? Ou isto é algo como um bug? Parece quase como que || e && têm a mesma prioridade, e a coisa toda é avaliada a partir do lado esquerdo, e os curto-circuitos ocorre e outras coisas. Se eu alterar o ++b==1 parte em ++b==0e , em seguida, a saída é o mesmo que eu previ.
Agradecemos antecipadamente por qualquer tipo de ajuda :)

1

Melhor resposta

4

A expressão a esta pergunta:

if(a++>0 || ++b==1 || c--<=0 && d++>c--)

é um exemplo clássico de uma horrível, horrível expressão, absurdamente irreal e impraticável, e punishingly difícil entender que, não obstante, faz um bom trabalho de ilustrar um super ponto importante: a precedência não é a mesma que a ordem de avaliação.

O que a precedência realmente nos diz é que, como os operadores são conectados com seus operandos. Assim, a expressão simplificada

A || B || C && D

que duas subexpressões fazer a primeira ||e o segundo ||e o && na verdade, unir e operar? Se você é um compilador escritor, responder a estas questões através da construção de uma "árvore de análise", que explicitamente mostra que subexpressão(s) vá com que os operadores.

Assim, dada a expressão A || B || C && Dnão , a árvore de análise para a expressão parecido com este:

        &&
       /  \
     ||    D
    /  \
  ||    C
 /  \
A    B

ou assim:

  ||
 /  \
A    ||
    /  \
   B    &&
       /  \
      C    D

ou assim:

      ||
     /  \
    /    \
  ||      &&
 /  \    /  \
A    B  C    D

Para responder esta pergunta precisamos saber não apenas que a precedência de && é maior do que ||, mas também que || resta-associativa. Tendo em conta estes factos, a expressão

A || B || C && D

é analisado como se tivesse sido escrito

(A || B) || (C && D)

e, portanto, os resultados no terceiro dos três candidatos analisar árvores mostrei:

      ||
     /  \
    /    \
  ||      &&
 /  \    /  \
A    B  C    D

Mas agora estamos em uma posição para realmente ver como o "curto-circuito" comportamento do || e && operadores vai ser aplicado. Que "topo" || está indo para avaliar o seu lado esquerdo e, em seguida, se é falso, também, avaliar o lado direito. Da mesma forma, o menor || vai avaliar o seu lado esquerdo. Assim, não importa o que, A vai ficar avaliada primeiro. Para a expressão em questão original, que corresponde a a++ > 0.

Agora, a++>0 é falso, portanto, nós vamos ter que avaliar B, o que é ++b == 1. Agora, o que é verdadeiro, então o resultado da primeira || é "verdadeiro".

Assim, o resultado da segunda (topo) || operador também é "verdadeiro".

De modo que o lado direito do topo || o operador não tem de ser avaliada em todos.

De modo que toda a subexpressão contendo && não serão avaliados.

Assim, mesmo que && tinha a precedência mais alta, ele acabou sendo considerado o último, e (desde que o material para a esquerda envolvidos || e era verdade) não acabar ficando avaliada em tudo.

A linha inferior, como comecei por dizer, é que a precedência não determinar a ordem de avaliação.

Também, se não foi dito em outros lugares, isso é garantido, da esquerda para direita comportamento é apenas garantido para o || e && operadores (e, de uma forma diferente, para o ternário ?: operador). Se a expressão tivesse sido

A + B + C * D

ele poderia não ter sido verdade que, como eu disse anteriormente, "não importa o que, A vai ficar avaliada em primeiro lugar". Para operadores aritméticos como + e *, não há nenhuma maneira de saber se o lado esquerdo ou o lado direito vai ficar avaliada primeiro.

2021-11-24 12:41:40

Completa e Racional. Obrigado mais uma vez muito.
III_phr

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................