Frage

Ich weiß, dass cout haben vor einigen Tagen puffern, und wenn ich es googeln, es wird gesagt, dass der Puffer einige wie ein Stapel ist und die Ausgabe von cout und printf von rechts nach links bekommen, so dass sie dann (nach löschte Konsole oder Datei) von oben nach bottem. Wie diese

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)

Dann schreibe ich einen Code unten,

#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; 
}

Unter VS2005, der Ausgang ist

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

Es scheint, dass der Stapel Weg richtig ist ~ Allerdings habe ich gelesen, C ++ Primer plus gestern, und es wird gesagt, dass die cout Arbeit von links nach rechts, kehrt jedes Mal ein Objekt (cout), so: „Das ist die Funktion, die Sie mit Bestueckdatenausgabe verketten läßt“. Aber die von rechts nach links Weg kann nicht erklären, cout <

Dann Alnitak mir zu sagen, dass „Der Operator << wirklich Ostream ist & operator << (ostream & os, int), so eine andere Art und Weise des Schreibens ist dies: operator << (operator << (operator << (cout, a), b), c)“

Wenn das Gesetz rechts Argument zuerst ausgewertet wird, kann es einige erläutert werden.

Jetzt bin ich verwirrt darüber, wie Puffer Arbeit cout, kann mir jemand helfen?

War es hilfreich?

Lösung

Sie sind eine Menge Dinge zu mischen. Bis heute:

  • Implementierungsdetails von cout
  • Chained Anrufe
  • Aufrufkonventionen

Versuchen Sie, auf sie separat zu lesen. Und denken Sie nicht über alle von ihnen in einem Rutsch.

  

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

Die obige Zeile ruft nicht definiertes Verhalten. Lesen Sie die häufig gestellten Fragen 3.2 . Beachten Sie, was Sie beobachten, ist ein Nebeneffekt der Aufrufkonvention Funktion und die Art und Weise Parameter werden in dem Stapel durch eine bestimmte Implementierung (das heißt bei Ihnen) übergeben. Dies ist nicht garantiert die gleiche sein, wenn Sie auf anderen Maschinen gearbeitet haben.

Ich glaube, Sie die Reihenfolge der Funktion sind verwirrend Anrufe mit Pufferung. Wenn Sie eine cout Anweisung gefolgt von mehreren Einfügungen haben << Sie tatsächlich mehrere Funktionsaufrufe, eine nach der anderen berufen sich. Also, wenn Sie sind schreiben:

cout << 42 << 0;

Es ist wirklich bedeutet: Sie rufen,

cout = operator<<(cout, 42)

und verwenden Sie dann die Rückkehr in einen anderen Anruf zu demselben Betreiber wie:

cout = operator<<(cout, 0)

Was Sie durch die oben getestet haben, werden Sie nichts cout internen Darstellung erzählen. Ich schlage vor, Sie an den Header-Dateien einen Blick mehr wissen.

Andere Tipps

So wie ein allgemeiner Tipp, niemals immer ich in der gleichen Zeile wie eine andere Nutzung von i ++ oder i -.

Das Problem ist, dass die Funktionsargumente in beliebiger Reihenfolge ausgewertet werden können, so dass, wenn Ihre Funktionsargumente Nebenwirkungen haben (wie die Erhöhungs- und Verringerungsoperationen) Sie können nicht garantieren, dass sie in der Reihenfolge arbeiten werden Sie erwarten. Das ist etwas, zu vermeiden.

Das gleiche gilt für diesen Fall, die an die tatsächliche Erweiterung Ihrer cout Nutzung ähnelt:

function1 (function2 (foo), bar);

Der Compiler ist frei bar evaulate vor function2 Aufruf, oder umgekehrt. Sie können, dass function2 garantieren Rückkehr vor function1 genannt wird, zum Beispiel, aber nicht, dass ihre Argumente in einer bestimmten Reihenfolge ausgewertet werden.

Dies wird zu einem Problem, wenn Sie so etwas wie:

function1 (function2 (i ++), i);

Sie haben keine Möglichkeit, zu bestimmen, ob die „i“ vor oder nach der „i ++“ bewertet, so dass Sie wahrscheinlich Ergebnisse zu erhalten, die anders sind, als Sie erwarten, oder unterschiedliche Ergebnisse mit unterschiedlichen Compilern oder sogar verschiedenen Versionen der gleiche Compiler.

Unterm Strich vermeiden Aussagen mit Nebenwirkungen. Nur nutzen sie, wenn sie die einzige Aussage auf der Linie sind oder wenn Sie wissen, dass Sie nur die gleiche Variable einmal ändern. (A "Linie" bedeutet eine einzelne Anweisung und Semikolon).

Was Sie sehen, ist nicht definiertes Verhalten.

Lokale i und globale c werden addiert / subtrahiert mehrere Male ohne Sequenzpunkt. Dies bedeutet, dass Werte, die Sie können über alles bekommen sein. Hängt davon ab, Compiler, möglicherweise auch Prozessorarchitektur und die Anzahl der Kerne.

Der cout Puffer kann als Warteschlange gedacht werden, so Alnitak richtig ist.

Zusätzlich zu den anderen Antworten, die aus richtig hinweisen, dass Sie nicht definiertes Verhalten sehen, dachte ich, ich würde erwähnen, dass std::cout verwendet ein Objekt vom Typ std::streambuf seine interne Pufferung zu tun. Im Grunde ist es eine abstrakte Klasse ist, die aus Puffer darstellt (die Größe ist insbesondere zur Implementierung und sogar 0 für unbufferd Strompuffer sein kann). Die eine für std::cout geschrieben, so dass, wenn es „überläuft“ es in stdout gespült wird.

In der Tat, können Sie die std::streambuf mit std::cout (oder einen Strom für diese Angelegenheit) zugeordnet ändern. Diese oft nützlich, wenn Sie etwas klug wie tun wollen machen alle std::cout fordert Ende in einer Log-Datei oder so etwas.

Und wie sagte dirkgently sind verwirrend Aufrufkonvention mit anderen Details, sind sie völlig unabhängig :: cout der Pufferung std.

Zusätzlich Ausgang Paradigmen Mischen (printf und cout) ist implementierungsspezifisch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top