Zum Inhalt springen

Empfohlene Beiträge

Geschrieben

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?

Geschrieben
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???

Geschrieben

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?

Geschrieben

Ü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.

Geschrieben

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.

Geschrieben

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?

Geschrieben

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.

Geschrieben

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

Geschrieben

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

Geschrieben

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.

Geschrieben
Originally posted by Stevie

Das heißt IMHO, dass eine cout-Kette nur von links nach rechts ausgewertet werden kann

Nein, 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.

Geschrieben
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]

Geschrieben

Ö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)

  • 2 Wochen später...
Geschrieben

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

Geschrieben
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.

Geschrieben

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

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.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...