Fine di verificare le condizioni in C

0

Domanda

Così stavo leggendo l'ordine di diversi operatori, e ho letto che && ha maggiore importanza rispetto a || e sarebbe valutare prima (fonte). Poi qualcuno mi ha chiesto una domanda su questo pezzo di codice stampa:

#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 ho pensato che la c-- <= 0 && d++ > c-- di valutare in primo luogo, che è vero in totale. dopo il processo, c sarebbe pari a -2 e d dovrebbe essere uguale a 1. Quindi si potrebbe iniziare a controllare il lato sinistro, la valutazione a++ > 0 || ++b == 1 il che è vero, a sarebbe 1 alla fine e b è 1 in condizione e dopo. pertanto il totale condizione non sarebbe true || true ed è vero, così ci sarà di stampa:

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

Sì? A quanto pare, no. Ho provato con GCC (Mingw) sul mio sistema (Windows 10), e con un compilatore online (questo) e su carta stampata:

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

Ho cambiato la condizione in questo: if(a++>0 || ++b==1 || (c--<=0 && d++>c--) ) ma l'uscita è esattamente la stessa cosa in entrambi i luoghi. C'è qualcosa che io non prestare attenzione? O si tratta di qualcosa come un bug? Sembra quasi che || e && hanno la stessa priorità, e il tutto viene valutato dal lato sinistro, e i corto circuiti verifica e di altre cose. Se cambio il ++b==1 parte in ++b==0allora l'uscita è la stessa come avevo previsto.
Grazie in anticipo per qualsiasi tipo di aiuto :)

1

Migliore risposta

4

L'espressione in questa domanda:

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

è un classico esempio di un orribile, orribile espressione, scandalosamente poco realistico e poco pratico, e punishingly difficile da capire, che, tuttavia, fa un buon lavoro di illustrare un super punto importante: in precedenza non è lo stesso ordine di valutazione.

Cosa precedenza veramente ci dice come gli operatori sono collegati con i loro operandi. Quindi, dato l'espressione semplificata

A || B || C && D

che due sottoespressioni fare il primo ||e il secondo ||e il && in realtà legare insieme e operare? Se sei un compilatore scrittore, si risponde a queste domande attraverso la costruzione di un "parse tree", che esplicitamente indica che parentetica(s) vai con cui gli operatori.

Così, data l'espressione A || B || C && Dnon l'albero sintattico dell'espressione simile a questa:

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

o come questa:

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

o come questa:

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

Per rispondere a questo, abbiamo bisogno di sapere non solo che la precedenza di && è superiore ||ma anche che || è associatività da sinistra a destra. Alla luce di questi fatti, l'espressione

A || B || C && D

viene analizzato come se fosse stata scritta

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

e, pertanto, i risultati del terzo dei tre candidati di analizzare gli alberi mi ha mostrato:

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

Ma ora siamo in una posizione veramente vedere quanto il "corto circuito" il comportamento del || e && gli operatori sta per essere applicato. Che il "top" || sta per valutare la sua mano sinistra, e poi, se è falso, valutare anche la destra. Allo stesso modo, inferiore || sta per valutare la sua sinistra. Così, non importa cosa, A sta per arrivare valutato per primo. Per l'espressione nella domanda originale, che corrisponde a a++ > 0.

Ora, a++>0 è falso, quindi stiamo andando ad avere per valutare Bche è ++b == 1. Ora, che è vero, quindi, il risultato del primo || è "vero".

Così il risultato del secondo (ultimo) || l'operatore è anche "vero".

In modo che il lato destro della parte superiore || l'operatore non deve essere valutata.

Così tutta la sottoespressione contenente && non sarà valutata.

Così, anche se && aveva la precedenza più alta, è finito per sempre considerati ultima, e (siccome la roba di sinistra coinvolti || ed era vero) non finiscono con l'essere valutata.

La linea di fondo, come ho iniziato da dire, è che la precedenza non si determina l'ordine di valutazione.

Inoltre, se non è stato detto altrove, questo è garantito, da sinistra a destra comportamento è solo garantito per il || e && gli operatori (e, in un modo diverso, per il ternario ?: operatore). Se l'espressione era stata

A + B + C * D

sarebbe non essere stato vero che, come ho detto in precedenza, "non importa cosa, A sta per arrivare valutato per primo". Per gli operatori aritmetici come + e *c'è modo di sapere se la sinistra o la destra sta per arrivare valutato per primo.

2021-11-24 12:41:40

Completa e Razionale. Grazie ancora tanto.
III_phr

In altre lingue

Questa pagina è in altre lingue

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