Decremento della differenza di operatore tra C ++ e Java? [chiuso]

1

Per favore dimmi perché lo stesso codice si comporta diversamente in C ++ e JAVA.

Ok prima implemento una funzione per calcolare il fattoriale di un Int RECURSIVELY

In JAVA:

int f(int x)
    {

        if(x==1)return 1;
        return(x*f(x-1));
    }

System.out.println (f (5)); ----- > uscite 120, ok ha senso.

METODO JAVA 2:

int f(int x)
    {

        if(x==1)return 1;
        return(x*f(--x));
    }

System.out.println (f (5)); ----- > uscite 120, ok anche questo ha senso.

Ma ecco una svolta in C ++:

METODO C ++ 1:

int f(int x)
{
    if(x==1)return 1;
    return (x*f(x-1));

}

cout < < f (5); ----- > uscite 120, ok ora continua a leggere!

METODO C ++ 2:

int f(int x)
{
    if(x==1)return 1;
    return (x*f(--x));

}

cout < < f (5); ----- > uscite 24. Questo è sorprendente. Ma perché ??

Ho provato a rintracciarlo più volte e ho fallito. Ha senso in java perché ogni chiamata ricorsiva ottiene il proprio pezzo di memoria e l'operatore di pre-decremento diminuirà e produrrà il valore diminuito. Perché funziona come previsto in JAVA ma non in C ++?

    
posta superspacemarines 01.05.2013 - 22:58
fonte

1 risposta

9
f1(int x)
{
  if(x = 1) return 1;
  return (x * f1(--x));
}

vs

int f2(int x)
{
    if(x==1)return 1;
    return (x * f2(x-1));
}

Il bit interno del codice f1 viene compilato su ( gcc -S ... ):

.L2:
    subl    $1, -4(%rbp)
    movl    -4(%rbp), %eax
    movl    %eax, %edi
    call    f1
    imull   -4(%rbp), %eax

Mentre f2 si compila in

.L2:
    movl    -4(%rbp), %eax
    subl    $1, %eax
    movl    %eax, %edi
    call    f2
    imull   -4(%rbp), %eax

Puoi vedere che le operazioni di subl e movl sono in un ordine diverso tra i due. In particolare, f1 sta sottraendo prima prima che il valore venga spostato perché venga utilizzato nel calcolo.

f1 ha un effetto collaterale di modificare il valore di x quando richiama --x . Questo effetto collaterale è un ordine in modo che accada al valore prima che il multiplo venga valutato con lo stesso valore .

In f1, hai:

First invocation
x = 5; x * f1(--x) --> x = 4 ; x * f1(4)

Second invocation
x = 4; x * f1(--x) --> x = 3 ; x * f1(3)

Third invocation
x = 3; x * f1(--x) --> x = 2 ; x * f1(2)

Fourth invocation
x = 2; x * f1(--x) --> x = 1 ; x * f1(1)

    
  

Ora hai popolato questi valori:

x = 1 ; x * f1(1) ; 1 * 1 --> return 1

             

x = 2 ; x * f1(2) ; 2 * 1 --> return 2

    
         

x = 3 ; x * f1(3) ; 3 * 2 --> return 6

  
     

x = 4 ; x * f1(4) ; 4 * 6 --> 24

Questo perché ti trovi in un'area indefinita del compilatore quando fai x * --x . Per consentire determinate ottimizzazioni, alcune cose devono essere indefinite. Questo è uno di questi: il compilatore può elaborarlo come vuole.

Non utilizzare --x o x-- a meno che non desideri la modifica dell'assegnazione.

so I was thinking that x will be always evaluated before --x. please tell me why I am wrong here? The compiler should not therefore try to optimize in these types of situations

Da wikipedia:

A sequence point defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.

Non c'è nessun punto di sequenza nell'espressione x * --x , quindi non c'è alcun punto in cui il compilatore c garantirà che la valutazione avvenga in un certo ordine.

L' associatività di un operatore deve occuparsi di come viene analizzata un'espressione.

Considera 4 * 3 + 2 . L'associatività e la precedenza di * e + guarntees che viene analizzata come (4 * 3) + 2 .

Gli operatori matematici sono lasciati associati, mentre l'assegnazione è giusta associativa. Mentre 4 + 3 + 2 + 1 è analizzato come (((4 + 3) + 2) + 1) - non importa troppo con questo. Le assegnazioni sono giuste associate. a = b = c = 4 diventa (a = (b = (c = 4))) . Osserva da che parte è il gruppo delle parentesi.

Questo non ha alcun rapporto con la questione su quale lato di un termine matematico viene valutato per primo nel contesto di x * --x .

    
risposta data 01.05.2013 - 23:25
fonte

Leggi altre domande sui tag