Forum: Compiler & IDEs assoziativität, undefinded behaivour


von daniel (Gast)


Lesenswert?

<ccode>
#include <stdio.h>

int glob = 0;

int a(void) {
    glob = 1;
    printf("a\n");
    return 1;
}

int b(void) {
    glob = 2;
    printf("b\n");
    return 2;
}

int c(void) {
    glob = 3;
    printf("c\n");
    return 3;
}

int main() {
    printf("%i\n", glob);
    a()+b()+c();
    printf("%i\n", glob);
    return 0;
}
</ccode>

gehe ich Recht in der Annahme, dass ...

a) die Reihenfolge der Aufrufe durch Assoziativität
eindeuting festgelegt ist (+ left to right) printet
a
b
c

b) die zuweisung zu glob kein undefined behaivour provoziert, weil
Funktionsaufruf ein Sequenzpunkt ist.

c) undefined behavour wäre
glob = a() + b() + c() + ++glob;
oder wenn a einen int parameter nehmen würde
glob = a(glob++);
aber das hier ist vollkommen ok
glob = glob++, a();

möchte nur, dass ihr mich verifiziert :)

grüsse, daniel

von Chris (Gast)


Lesenswert?

AFAIK ist das alles kein well-formed code. Bei f() + g() ist (meine ich) 
nicht festgelegt, welche Funktion zuerst aufgerufen wird. Der Compiler 
wird sich natuerlich fuer eine entscheiden, aber welche, das steht ihm 
frei.

Bei f(g(), h()) bin ich mir sogar sicher, dass nicht festgelegt ist in 
welcher Reihenfolge die Parameter ausgewertet werden.

Davon ganz abgesehen: Selbst wenn das definiert waere, wuerde ich 
solchen Code niemals schreiben. Wenn du dir schon nicht sicher bist, wie 
sollen dann andere herausbekommen was die Zeile bedeutet? Wieso nicht 
einfach ein paar sequence points setzen?

a = f();
b = g();
c = h();
d = a + b + c;

von daniel (Gast)


Lesenswert?

Eigentlich ist der Hintergrund einfach die C und C++ Spezifikation 
aufzufrischen.
Dass die Evaluationsreihenfolge der Funktionsparameter dem Compiler
überlassen ist, das weiss ich. Ich bin mal böse auf die Schnauze
bei folgendem Code gefallen ...

#include <iostream>
#include <cstdlib>

int main() {
    int i = 0;
    std::cout << i << '\t' << ++i << std::endl;
    i = 0;
    std::cout.operator<<(i).operator<<('\t').operator<<(++i).operator<<(std: 
:endl);

    return EXIT_SUCCESS;
}

i und ++i sind hierbei ohne Sequenzpunkt auf einer Ebene sozusagen.
es ist nur weniger sichtbar wenn der Operator << heisst und nicht +

komischerweise wird '\t' als int in der 2-ten expliziten Aufrufform 
interpretiert.

grusse, daniel

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

daniel wrote:

> a) die Reihenfolge der Aufrufe durch Assoziativität
> eindeuting festgelegt ist (+ left to right) printet

Nein.  Assoziativität bedeutet nur, in welcher Reihenfolge die
Ergebnisse der Funktionsaufrufe bewertet werden, nicht aber, in
welcher die Funktionen aufgerufen werden.  Daher ist das Verhalten
bezüglich der Variablen glob undefined.

Es gibt nur wenige Dinge im C-Standard, die dem Compiler eine
Vorschrift auferlegen, in welcher Reihenfolge Dinge abzuarbeiten
sind.  Dazu gehört einerseits der Komma-Operator, andererseits
eine verkettete Bedingung.

von daniel (Gast)


Lesenswert?

hmm, Danke
aber irgendwie macht es keinen Sinn für mich, vielleicht misverstehe
ich etwas. Addition ist doch eine kommutative Operation, wozu dann
die Evalutationsreihenfolge (left to right) definieren?
Es scheint für mich zumindest nur dann Sinn zu machen, wenn
die Seiteneffekte (zB durch Körper der aufgerufenen Funktionen) ins 
Spiel kommen.

grüsse, daniel

von Karl H. (kbuchegg)


Lesenswert?

daniel wrote:

> ich etwas. Addition ist doch eine kommutative Operation, wozu dann
> die Evalutationsreihenfolge (left to right) definieren?

Wie willst du feststellen, dass die Reihenfolge left to right
bei Addition definiert ist oder nicht?

Der Compiler muss Code erzeugen, der das korrekte Ergebnis von
a + b (bei Integer) erzeugt.
Ob er das macht, indem er a in einem Register vorlegt und
in dieses Register b addiert, oder anders rum, ist völlig
dem Compiler belassen.


> Es scheint für mich zumindest nur dann Sinn zu machen, wenn
> die Seiteneffekte (zB durch Körper der aufgerufenen Funktionen) ins
> Spiel kommen.

Wenn Seiteneffekte ins Spiel kommen, ist so gut wie gar nichts
mehr garantiert. Brutal ausgedrückt.

von daniel (Gast)


Lesenswert?

hab dazu bei Wiki nochmals explizit die Antwort gefunden
http://de.wikibooks.org/wiki/C++-Programmierung:_Ausdr%C3%BCcke_und_Operatoren

int x = (a() + b()) + c();
sehe ich das richtig, die Klammerung bleibt also genauso erfolglos?
Sie würde die Precedence von 1 Plus erhöhen, aber Reihenfolge
ist ein dazu orthogonales Konzept?

mir fällt gerade ein Vergleich ein
bei f(a(),b(),c()) .. wie die meisten in diesem Fall wissen,
kann die Reihenfolge beliebig sein.
Wenn man sich jetzt f(x,y,z) als x+y+z implementiert denkt, so
sind x,y,z nichts anderes als Parameter dieser Funktion f.
Und Parameter werden beliebig zu ihrem Wert evaluirt.
Vielleicht einwenig weithergehollt, aber als Eselsbrücke geeignet :)

grüsse, Daniel

von Karl H. (kbuchegg)


Lesenswert?

daniel wrote:
> hab dazu bei Wiki nochmals explizit die Antwort gefunden
> http://de.wikibooks.org/wiki/C++-Programmierung:_Ausdr%C3%BCcke_und_Operatoren
>
> int x = (a() + b()) + c();
> sehe ich das richtig, die Klammerung bleibt also genauso erfolglos?

Das siehst du absolut 100% richtig.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:

> Das siehst du absolut 100% richtig.

Ergänzung: die Klammern sind ja völlig redundant, da sie nur das
ausdrücken, was ohnehin bereits der Fall ist.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.