Domanda

So che cout ha un buffer diversi giorni fa, e quando lo cerco su Google, si dice che il buffer è simile a uno stack e ottiene l'output di cout e printf da destra a sinistra, quindi li pubblica (sulla console o sul file )dall'alto verso il basso.Come questo,

a = 1; b = 2; c = 3;
cout<<a<<b<<c<<endl;
buffer:|3|2|1|<-   (take “<-” as a poniter)

output:|3|2|<-     (output 1)
        |3|<-       (output 2)
        |<-         (output 3)

Quindi scrivo un codice qui sotto,

#include <iostream> 
using namespace std; 
int c = 6;
int f() 
{   
    c+=1; 
    return c; 
} 

int main() 
{ 
     int i = 0; 
     cout <<"i="<<i<<" i++="<<i++<<" i--="<<i--<<endl; 
     i = 0;
     printf("i=%d i++=%d i--=%d\n" , i , i++ ,i-- );

     cout<<f()<<" "<<f()<<" "<<f()<<endl; 
     c = 6;
     printf("%d %d %d\n" , f() , f() ,f() );
     system("pause");
     return 0; 
}

Sotto VS2005, l'output è

i=0 i++=-1 i--=0
i=0 i++=-1 i--=0
9 8 7
9 8 7

Sembra che il modo stack sia giusto ~ Tuttavia, ho letto C ++ Primer Plus ieri, e si dice che il lavoro di copertura da sinistra a destra, ogni volta restituire un oggetto (cout), quindi "questa è la caratteristica che ti consente di concatenare l'output Usando l'inserimento ".Ma il modo da sinistra a destra non può spiegare cout<

Poi Alnitak dimmi che "L'operatore << è in realtà ostream& operator<<(ostream& os, int), quindi un altro modo di scriverlo è:operatore<< ( operatore<< ( operatore<< ( cout, a ), b ), c ​​)",

Se viene valutato per primo l'argomento più giusto, è possibile spiegarlo in parte.

Ora sono confuso su come funziona il buffer di cout, qualcuno può aiutarmi?

È stato utile?

Soluzione

Stai mescolando un sacco di cose.Ad oggi:

  • Dettagli di implementazione di cout
  • Chiamate concatenate
  • Convocazione di convenzioni

Prova a leggerli separatamente.E non pensare a tutti in una volta.

printf("i=%d i++=%d i--=%d " , i , i++ ,i-- );

La riga precedente richiama un comportamento indefinito.Leggi le domande frequenti 3.2.Nota, ciò che osservi è un effetto collaterale della convenzione di chiamata della funzione e del modo in cui i parametri vengono passati nello stack da una particolare implementazione (ad es.il tuo).Non è garantito che sia lo stesso se lavorassi su altre macchine.

Penso che tu stia confondendo l'ordine delle chiamate di funzione con il buffering.Quando hai un cout frase seguita da più inserimenti << stai effettivamente invocando più chiamate di funzione, una dopo l'altra.Quindi, se dovessi scrivere:

cout << 42 << 0;

Significa davvero:Chiami,

cout = operator<<(cout, 42)

e quindi utilizzare il ritorno in un'altra chiamata allo stesso operatore di:

cout = operator<<(cout, 0)

Ciò che hai testato con quanto sopra non ti dirà nulla coutla rappresentazione interna.Ti suggerisco di dare un'occhiata ai file header per saperne di più.

Altri suggerimenti

Proprio come un suggerimento generale, mai e poi mai usare i ++ nella stessa linea come un altro utilizzo di I o i -.

Il problema è che gli argomenti delle funzioni possono essere valutati in qualsiasi ordine, quindi se i vostri argomenti della funzione hanno effetti collaterali (come ad esempio le operazioni di incremento e decremento), non si può garantire che opereranno secondo l'ordine che ci si aspetta. Questa è una cosa da evitare.

Lo stesso vale per questo caso, che è simile alla effettiva espansione del vostro utilizzo cout:

funzione1 (function2 (foo), bar);

Il compilatore è libero di evaulate bar prima di chiamare function2, o viceversa. Si può garantire che function2 tornerà prima funzione1 è chiamato, per esempio, ma non è che i loro argomenti vengono valutati in un ordine specifico.

Questo diventa un problema quando si fa qualcosa di simile:

funzione1 (funzione2 (i ++), i);

Non hai modo di specificare se la "i" viene valutata prima o dopo la "i ++", quindi è molto probabile che per ottenere i risultati che sono diverse da quelle che ci si aspetta, o risultati diversi con compilatori diversi o anche diverse versioni di lo stesso compilatore.

Linea di fondo, evitare affermazioni con effetti collaterali. usarli solo se sono l'unica dichiarazione sulla linea o se sai che stai modificando solo la stessa variabile una volta. (Una "linea" si intende una singola istruzione più e virgola.)

Quello che vedete è un comportamento indefinito.

i

locali c e globali vengono aggiunti / sottratti più volte senza punto di sequenza. Ciò significa che i valori si ottiene può essere qualsiasi cosa. Dipende compilatore, eventualmente anche architettura del processore e il numero di nuclei.

Il cout buffer può essere pensato come coda, in modo Alnitak è giusto.

In aggiunta alle altre risposte che indicano giustamente che si sta vedendo un comportamento indefinito, ho pensato di ricordare che std::cout utilizza un oggetto di tipo std::streambuf per fare il suo buffer interno. Fondamentalmente è una classe astratta che rappresenta di tampone (la dimensione è particolare implementazione e può anche essere 0 per i buffer flusso unbufferd). Quello per <=> è scritto in modo tale che quando si "trabocca" viene lavata in stdout.

In realtà, è possibile modificare il <=> associata a <=> (o qualsiasi flusso per quella materia). Questo spesso utile se si vuole fare qualcosa di intelligente come fare tutti <=> chiamate fine a un file di log o qualcosa del genere.

E come dirkgently detto si stanno confondendo convenzione di chiamata ad altri dettagli, sono del tutto estranei a std :: buffer di cout.

Inoltre, mescolando paradigmi uscita (printf e cout) sono specifica implementazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top