Stevie Geschrieben 31. März 2003 Geschrieben 31. März 2003 Hi, ich habe eine Frage zu folgendem kleinen Programm (erstellt mit Visual Studio): #include <iostream.h> void main() { int x = 10; cout << x << " " << (x = 11) << endl; cout << (x = 10) << " " << x << endl; } Folgende Ausgabe erscheint: 11 11 10 11 Es scheint doch so, dass die Kette von rechts nach links abgearbeitet wird. Das versteh ich nicht so ganz. Spricht das nicht gegen die Überladung von Funktionen bzw. Operatoren? Ich dachte, solche Ketten werden auch so abgearbeitet, wie sie ausgegeben werden. Kann mir das jemand erklären? Zitieren
Guybrush Threepwood Geschrieben 31. März 2003 Geschrieben 31. März 2003 Hi, ich verstehe dein Problem irgendwie nicht. Wie du ja schon geschrieben hast, wird die Ausgabe von rechts nach links verarbeitet und dementsprechend ist ja auch die Ausgabe, aber was soll da jetzt flasch sein? Gruß Guybrush Zitieren
Stevie Geschrieben 31. März 2003 Autor Geschrieben 31. März 2003 Originally posted by Guybrush Threepwood dementsprechend ist ja auch die Ausgabe Öhm, die Ausgabe ist doch von links nach rechts. Der Befehl cout << "Hallo " << "Welt!"; ergibt ja auch nicht "Welt!Hallo ". Meine Frage ist, ob cout intern die Ausdrücke von rechts nach links arbeitet und dann von links nach rechts ausgibt, oder wie??? Zitieren
Guybrush Threepwood Geschrieben 31. März 2003 Geschrieben 31. März 2003 Ja klar die Ausgabe ist schon von Links nach rechts, anhand der << Operatoren baut sich cout einen String zusammen der dann ganz normal ausgegeben wird. Dieser << Operator ist, wie die meisten, von rechts nach links. BSP.: int x=0; int y=5; int a=y=x=6; Danach haben alle Variablen den Wert 6 und nicht a den Wert 5, y den Wert 0 und x den Wert 0. Klar was ich meine, oder hab ich mich undeutlich ausgedrückt? Zitieren
Stevie Geschrieben 31. März 2003 Autor Geschrieben 31. März 2003 Ach, so hab ich das garnicht gesehen. Jo, jetzt ist's klar! Thanks Piepwutt! Zitieren
Klotzkopp Geschrieben 31. März 2003 Geschrieben 31. März 2003 Übrigens: In welcher Reihenfolge hier die Operatoren ausgewertet werden, kann sich der Compilerhersteller aussuchen. Das kann also mit einen anderen Compiler schon wieder ganz anders aussehen. Wenn man portablen Code schreiben will, sollte man auf solche Konstrukte verzichten. Zitieren
Stevie Geschrieben 31. März 2003 Autor Geschrieben 31. März 2003 Wenn ich mich recht erinnere, wertet zum Beispiel der Borland-Compiler von links nach rechts aus, gell? Zitieren
Crush Geschrieben 31. März 2003 Geschrieben 31. März 2003 Auch strcmp() liefert bei Borland andere Ergebnisse als Microstoff (hab ich irgendwo in meinen Büchern mit großem ! stehen). Grundsätzlich scheinen beide bei String-Operationen auseinanderzudriften. Zitieren
nic_power Geschrieben 1. April 2003 Geschrieben 1. April 2003 Hast Du da mal einen Link für? strcmp() gehört zur Standardbibliothek und sollte daher auf allen Systmene konsistente Ergebnisse liefern. Nic Zitieren
Crush Geschrieben 1. April 2003 Geschrieben 1. April 2003 Ich habe nochmal im Buch nachgeschlagen und es auf anhieb gefunden (aber keinen Link, vielleicht ist das Problem auch nicht mehr aktuell, obwohl das Buch von 1999 ist, also schon nach der Standardisierung rauskam!) Beispielprogramm: #include <stdio.h> #include <string.h> int main (void) { printf ("%d\n", strcmp ("abcde", "abCde")); // 1 printf ("%d\n", strcmp ("abcde", "abcde")); // 2 printf ("%d\n", strcmp ("abcd", "abcde")); // 3 return 0; } Borland soll diese Ergebnisse liefern: 1) 32 2) 0 3)-101 MSV diese: 1) 1 2) 0 3)-1 Vielleicht kann ja mal jemand das Programm auf Borland-Compilern austesten. Evtl. ist dieses Problem nicht mehr aktuell und das Buch somit veraltet? Zitieren
Klotzkopp Geschrieben 2. April 2003 Geschrieben 2. April 2003 Der Standard gibt als Rückgabewerte von strcmp keine bestimmten Werte, sondern nur Null, größer als Null und kleiner als Null an. Diesbezüglich verhalten sich beide Compiler standardgemäß. Ein "Problem" kann da IMHO nur auftreten, wenn der Programmierer sich auf bestimmte Rückgabewerte verlässt oder die Werte noch irgendwie interpretiert. Zitieren
nic_power Geschrieben 2. April 2003 Geschrieben 2. April 2003 Hallo, Aus dem Grund sollte man sich ja auch an den Sprachstandard halten (>0, ==0, <0 als Rückgabewert). Eine direkte Verwendung der Rückgabewerte ist nicht standardkonform. Nic Zitieren
Stevie Geschrieben 3. April 2003 Autor Geschrieben 3. April 2003 Nochmal zurück zu unserem Ausgangsproblem: Ich hab mit meinem Programmieren-Lehrer in der Berufsschule gesprochen und er meint, ein Ausdruck wie cout << "Hallo " << "Welt!"; würde erst cout << "Hallo " verarbeiten und dann cout als Präferenz zurückliefern. Dann würde somit der Ausdruck cout << "Welt!" verarbeitet. Ich blick da aber nicht ganz durch. Übrigens hab ich folgendes mal ausprobiert: #include <iostream.h> void main() { int x = 10; int y = 20; int z = 30; x = y = z = 40; cout << x << " " << y << " " << z << endl; } Tja, und raus kam das: 40 40 40 Zitieren
Orffi Geschrieben 3. April 2003 Geschrieben 3. April 2003 Wo liegt das Problem? (Abgesehen davon, daß das Programm überhaupt nicht dem C++ Standard entspricht...) Ist doch klar, daß dreimal 40 ausgegeben wird, denn in der Zeile darüber weist Du z den Wert 40 zu, der y zugewiesen wird und dann x zugewiesen wird. HTH Jan Zitieren
Stevie Geschrieben 3. April 2003 Autor Geschrieben 3. April 2003 Ups, verschreibt: Ich meinte: cout << x << " "<< y << " "<< z << " "<< (x=y=z=40) << " " << x; Ausgabe: 40 40 40 40 10 Liegt aber am Compiler, weil bei Linux was anderes rauskommt. Ich hab mir aber die Definition des operators<< angeguckt. Dort wird praktisch der R-Wert ausgeben und der L-Wert per return zurückgeliefert. Das heißt IMHO, dass eine cout-Kette nur von links nach rechts ausgewertet werden kann (siehe mein vorheriger Post), weil ja z.B. mit " " << x nix angefangen werden kann. Aber irgendwie muss hier ja von rechts nach links gearbeitet werden, sonst würde die Ausgabe ja anders ausgehen, gell? Ich hoffe, jetzt hab ich mich einigermaßen klar ausgedrückt. Zitieren
Klotzkopp Geschrieben 3. April 2003 Geschrieben 3. April 2003 Originally posted by Stevie Das heißt IMHO, dass eine cout-Kette nur von links nach rechts ausgewertet werden kannNein, weil des dem Compiler überlassen bleibt, in welcher Reihenfolge die Argumente des operator<< abgearbeitet werden. Ich habe deinen Ausdruck mal so umgestellt, dass die operator<<-Aufrufe ausgeschrieben und die Leerzeichen weg sind: op<<(op<<(op<<(op<<(op<<(cout,x), y), z), x=y=z=40), x) Der Compiler kann sich jetzt aussuchen, welches Funktionsargument er zuerst auswertet. Die Reihenfolge, in der x, y, z, x (Ref. Nummer 2), cout und die Zuweisungen ausgewertet werden, ist undefiniert. Zitieren
Stevie Geschrieben 3. April 2003 Autor Geschrieben 3. April 2003 Kannst du mir diesen Befehl nochmal in ausführbarem C-Code ausschreiben? Ich meine so, dass auch was ausgegeben wird. Zitieren
Klotzkopp Geschrieben 3. April 2003 Geschrieben 3. April 2003 Originally posted by Stevie Kannst du mir diesen Befehl nochmal in ausführbarem C-Code ausschreiben?Klar. Es sieht übrigens etwas anders aus als in meinem vorherigen Beitrag, weil ich nicht daran gedacht habe, dass der operator<<(int) ein Member von basic_ostream ist. operator<<( operator<<( operator<<( operator<<( cout.operator<<(x)," " ).operator<<(y)," " ).operator<<(z), " " ).operator<<(x=y=z=40)," " ).operator<<(x);[/CODE] Zitieren
Stevie Geschrieben 3. April 2003 Autor Geschrieben 3. April 2003 Öhm, nö, funzt nicht! #include <iostream.h> void main() { int x = 10; int y = 20; int z = 30; operator<<( operator<<( operator<<( operator<<( cout.operator<<(x)," " ).operator<<(y)," " ).operator<<(z), " " ).operator<<(x=y=z=40)," " ).operator<<(x); } Fehlermeldung: --------------------Konfiguration: Test - Win32 Debug-------------------- Kompilierung läuft... Test.cpp C:\...\Test.cpp(13) : error C2065: '<<' : nichtdeklarierter Bezeichner C:\...\Test.cpp(13) : error C2228: Der linke Teil von '.<<' muss eine Klasse/Struktur/Union sein C:\...\Test.cpp(13) : error C2228: Der linke Teil von '.<<' muss eine Klasse/Struktur/Union sein C:\...\Test.cpp(13) : error C2228: Der linke Teil von '.<<' muss eine Klasse/Struktur/Union sein C:\...\Test.cpp(13) : error C2228: Der linke Teil von '.<<' muss eine Klasse/Struktur/Union sein Fehler beim Ausführen von cl.exe. Test.exe - 5 Fehler, 0 Warnung(en) Zitieren
Klotzkopp Geschrieben 3. April 2003 Geschrieben 3. April 2003 #include <iostream> using namespace std; int main() {[/CODE] Zitieren
Stevie Geschrieben 3. April 2003 Autor Geschrieben 3. April 2003 Jepp, klappt, danke!!! Jetzt blick ich auch dahinter. :bimei Zitieren
A-RAM Geschrieben 16. April 2003 Geschrieben 16. April 2003 hmm das Problem (welches keines ist) ist nicht in C++ und Operatoren zu suchen, denn: int x = 10; printf("%i %i\n", x, (x=11)); gibt auch 11 11 aus. Operatoren wie << sind ja im Endeffekt nur Funtkionen. Das Problem ist eine Stufe tiefer zu suchen im nativen Assemblercode. In Assembler kann man ähnlich wie in C Funktionen mittels call aufrufen. Die Argumente wergen mit Hilfe des Stacks übergeben. Da der Stack ein Kellerspeicher ist und das aktuellste Element immer an oberster Stelle liegt und auch nur von dort wieder genommen werden kann, übergibt man in Assembler die Argumente rückwärts, damit die aufgerufene Funktion die Argumente wieder in richtiger Reihenfolge vom Stack holen kann und somit auch Funktionen wie z.Bsp. dividiere(x, y) mit richtiger Reihenfolge der Ausdrücke ausführen kann. der Code würde in etwa so aussehen: ;____Verarbeitung Ausdruck 1______ = 2. Argument in C mov eax, x ; x in eax laden add 11 ; 11 auf eax aufaddieren mov x, eax ; eax in x zurückspeichern push eax ; eax auf den Stack laden ;____Verarbeitung Ausdruck 2______ = 1. Argument in C mov eax, x ; x erneut in eax laden push eax ; eax auf den Stack laden ;_________printf aufrufen__________ call printf ;... ;___________in printf______________ pop eax ; Ausdruck 2 vom Stack in eax laden pop edx ; Ausdruck 1 vom Stack in edx laden ;... verarbeiten Das "Problem" liegt darin, das du x=11 zuweist, und dieser Ausdruck zuerst ausgewertet wird, bevor er auf den Stack gelegt wird. Und wärend dieser Auswertung sagst du ihm ja, er soll 11 in x legen, womit du x änderst, und er dann erst das geänderte x an sich auf den Stack legt. mfg A-RAM Zitieren
Klotzkopp Geschrieben 17. April 2003 Geschrieben 17. April 2003 Original geschrieben von A-RAM Das "Problem" liegt darin, das du x=11 zuweist, und dieser Ausdruck zuerst ausgewertet wird, bevor er auf den Stack gelegt wird. Und wärend dieser Auswertung sagst du ihm ja, er soll 11 in x legen, womit du x änderst, und er dann erst das geänderte x an sich auf den Stack legt.Da verwechselst du etwas. Die Reihenfolge der Funktionsargumente auf dem Stack (und selbst das ist ein Implementierungsdetail) hat mit der Reihenfolge, in der die Argumente ausgewertet werden, nichts zu tun. Da hat der Compiler völlig freie Hand. Das einzige, was sicher ist, ist, dass alle Argumente ausgewertet werden, bevor die Funktion aufgerufen wird. Zitieren
nic_power Geschrieben 17. April 2003 Geschrieben 17. April 2003 Hallo, Original geschrieben von Klotzkopp Das einzige, was sicher ist, ist, dass alle Argumente ausgewertet werden, bevor die Funktion aufgerufen wird. Nachzulesen unter anderem in Stroustrup 5.2.2. @A-RAM: Es gibt auch Architekturen, die die Parameterübergabe nicht über den Stack realisieren, sondern über Register bzw. einen Register-Windowing Mechanismus. Du musst auch bei einem Stack nicht notwendigerweise immer auf erste Element zugreifen (durch Manipulation des Stackpointers ist im Prinzip jedes beliebige Element erreichbar). Nic Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.