[C] Hat x=x einen Seiteneffekt?

chaos

*nix'ler
Hallo,

ich hab eine mehr oder weniger philosophische Frage zu C und Seiteneffekten.

Dazu erstmal aus dem ISO-C-90-Standard (bzw. dem ANSI-Entwurf von diesem) die Definition von Seiteneffekt:
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects.

Also ist klar, dass bei
Code:
volatile int x=0;
x=x;
auch die zweite Zeile einen Seiteneffekt hat (Zugriff auf die volatile Variable hat einen Seiteneffekt, der Rest dient zur Verwirrung bzw. Vorbereitung der nächsten Frage).

Wie schaut es nun aber aus, wenn x nicht volatile ist?

Also hat bei
Code:
int x=0;
x=x;
die zweite Zeile einen Seiteneffekt, oder nicht?

Also ist das Zuweisen eines Wertes an eine Variable zwangsläufig eine Modifikation (d.h. Seiteneffekt) der Variable, oder nicht?
  • Zum einen könnte man antworten, dass im Fall, dass der Compiler nicht optimiert, sich die Register der CPU ändern können und dadurch ein Seiteneffekt geschen ist,
  • zum anderen könnte man auf Quelltextebene argumentieren, dass die Variable x dadurch ja nicht modifiziert wurde, also kein Seiteneffekt geschehen ist.
    Wenn die Antwort "kein Seiteneffekt lautet, dann kann man natürlich weiter gehen/fragen.

Hat bei
Code:
int x=0;
x=x+1-1;
die zweite Zeile einen Seitteneffekt?

Oder wie sieht es gar mit
Code:
int myzero(void)
{
        return 0;
}
int main(void)
{
        int x=0;
        x=myzero();
}
aus?
Gut bei dem Beispiel könnte man sagen dass der Compiler für den Rückgabewert von myzero eine Variable anlegt und dieser einen Wert zuweist (modifiziert), also ein Seiteneffekt entsteht?

Und zuletzt noch:
Code:
int global=0;
void globalzero(void)
{
    global=0;
}
Ist zur Compilezeit entscheidbar, ob ein Funktionsaufruf von globalzero() einen Seiteneffekt hat, oder sieht man die Zuweisung als Modifikation?

ciao
chaos

PS: Ich finde inzwischen nach etwas längerer Überlegung die Sichtweise der CPU als zustandsmaschine und evtl. geänderten Registerinhalten als Begründung für einen Seiteneffekt ganz sympatisch.
--------
[1]
Unter der Annahme, dass bei x=0 wohl bei den meisten Rechnerarchitekturen und Compilern die Integeraddition und anschließende Subtraktion noch gut geht, d.h. ohne Überlauf o.ä. und seltsamen nichtdefiniertem Verhalten aufgrund von freizügiger Undefivend-behavior-Auslegung.
 
Na ja, wenn du schon philosophisch wirst, müßtest du zunächst mal sagen was denn ein Seiteneffekt sei. In der funktionalistischen Sichtweise der Dinge ist jede Variable die ihren Wert ändern kann ein Seiteneffekt weshalb es in rein funktionalen Sprachen nur konstante Werte gibt.

Ich denke deine Frage ist weniger eine philosophische als die and language-lawyers und dazu kann ich nichts sagen. :rolleyes:
 
(Zugriff auf die volatile Variable hat einen Seiteneffekt, [...]).

Nein, Zugriff auf die volatile Variable ist der Seiteneffekt. Wie im Abschnitt zu lesen ist, geht es nicht darum, dass Zugriffe einen Seiteneffekt haben, sondern darum, dass sie Seiteneffekte sind. Es geht ja (meistens) nicht darum, dass du unbedingt auf die Speicherstelle von x zugreifen wolltest. Es ist nur der Seiteneffekt, dass genau das immer gemacht wird bei volatile.

Also hat bei
Code:
int x=0;
x=x;
die zweite Zeile einen Seiteneffekt, oder nicht?

Das ist kein Seiteneffekt. Du weist x einen Wert zu (na gut, den Wert von x). Aber du modifizierst das Objekt x nicht während der Auswertung des Ausdrucks "x" auf der rechten Seite des Zuweisungsoperators "=". Ein Seiteneffekt wäre es in der Form

Code:
x=x++;

Aber dann bist du auch gleich in einem undefinierten Zustand.

Also ist das Zuweisen eines Wertes an eine Variable zwangsläufig eine Modifikation (d.h. Seiteneffekt) der Variable, oder nicht?
  • Zum einen könnte man antworten, dass im Fall, dass der Compiler nicht optimiert, sich die Register der CPU ändern können und dadurch ein Seiteneffekt geschen ist,
  • zum anderen könnte man auf Quelltextebene argumentieren, dass die Variable x dadurch ja nicht modifiziert wurde, also kein Seiteneffekt geschehen ist.
    Wenn die Antwort "kein Seiteneffekt lautet, dann kann man natürlich weiter gehen/fragen.
Es geht in der Sprache C nicht um CPU-Register. Die Seiteneffekte beziehen sich nicht auf den Zustand von Registern, sondern rein auf C-Elemente. Und Inline-Assembler zählt nicht dazu. ;)

Hat bei
Code:
int x=0;
x=x+1-1;
die zweite Zeile einen Seitteneffekt?

Nein, auch hier ist kein Seiteneffekt. Du weist der Variablen x wieder einen Wert zu. Während der Auswertung des Ausdrucks "x+1-1" ändert sich nicht der Zustand von x.

Oder wie sieht es gar mit
Code:
int myzero(void)
{
        return 0;
}
int main(void)
{
        int x=0;
        x=myzero();
}
aus?

Auch hier gibt es nur eine Zuweisung.

Gut bei dem Beispiel könnte man sagen dass der Compiler für den Rückgabewert von myzero eine Variable anlegt und dieser einen Wert zuweist (modifiziert), also ein Seiteneffekt entsteht?

Was der Compiler daraus macht, ist dem Sprachstandard relativ egal. Rausoptimieren ist genauso gültig wie den Wert im Register zu halten oder auf den Stack zu legen oder was auch immer gerade am besten passt. Die Seiteneffekte beziehen sich auf C-Elemente; auf nichts anderes.

Und zuletzt noch:
Code:
int global=0;
void globalzero(void)
{
    global=0;
}
Ist zur Compilezeit entscheidbar, ob ein Funktionsaufruf von globalzero() einen Seiteneffekt hat, oder sieht man die Zuweisung als Modifikation?

Der Compiler kann das nicht wissen. Vielleicht kann eine Kombination aus Compiler und Linker entscheiden, ob man das Rausoptimieren kann. Aber mit dem Compiler kannst du zum Beispiel mit -c einzelne Dateien in Objektdateien schreiben und die zum Schluss zusammen verlinken. Woher sollte der Compiler beim Kompilieren von datei.c wissen, ob du nicht irgendwo noch eine datei2.c in das Programm verlinken wirst, die auf global zugreift?


Seiteneffekte hast du immer dann, wenn du Objekte modifizierst, auf die du im gleichen Ausdruck nochmal zugreifst.

Code:
x = a++ - b++;
y = a++ > 1 ? ++b : a++;

Und der zweite Ausdruck verdeutlicht wohl auch, warum Seiteneffekte gerne mal zur Verwirrung führen.
 
Umgangssprachlich ist der Begriff Seiteneffekt leicht zu erkennen, wenn du das Wort "übrigens" verwendest.

Code:
x = a++ - b++;

"x bekommt den Wert von a - b. Übrigens ist a ab jetzt um 1 erhöht und b übrigens auch."

Code:
y = a++ > 1 ? ++b : a++;

"Wenn a größer ist als 1, dann bekommt y den Wert von b+1. Übrigens habe ich dann a um 1 erhöht und b auch. Wenn stattdessen a nicht größer ist als 1, dann bekommt y den Wert a+1. Übrigens wird a dann um 2 erhöht."
 
Theoretisch wird der (in der Regel implizite) Copy-assignment operator aufgerufen. Wenn das der implizite ist, kann der Compiler das weg optimieren.

Wenn ein Eigener definiert ist hängt es vom Inhalt ab. Wenn der zum Beispiel einen statischen Copy-Zähler hoch zählt, ist Schluss mit weg optimieren. Das wäre dann ein Seiteneffekt (Zähler erhöhen).
 
Zunächst einmal ist das deutsche Wort für "side effect" "Nebenwirkung". Damit ist auch klarer, worum es hier geht: Manche Operatoren haben nicht nur ein Ergebnis, sondern haben auch noch eine Nebenwirkung. Das Ergebnis des =-Operators ist der neue Wert der linken Seite (so wie das Ergebnis von + die Summe der Operanden ist). Die Nebenwirkung ist das Verändern des Objektes, das durch die linke Seite bezeichnet wird. Hierbei ist es unerheblich, ob zufälligerweise der selbe Wert zugewiesen wird, den das Objekt schon inne hat. Die Nebenwirkung von "x = x" ist schlicht das Verändern des Objektes, das durch x benannt wird. Wobei Objekt hier im C-Sinne zu verstehen ist:
ISO/IEC 9899:2011 §3.15 schrieb:
region of data storage in the execution environment, the contents of which can represent
values

Zum Beispiel hat der Ausdruck "a = b = c++" drei Nebenwirkungen: a, b und c werden zugewiesen. Das Ergebnis des rechten = ist der neue Wert von b. Dieser wird an a zugewiesen. Das Ergebnis des linken = ist der neue Wert von a und wird verworfen.

paldium schrieb:
Das ist kein Seiteneffekt. Du weist x einen Wert zu (na gut, den Wert von x). Aber du modifizierst das Objekt x nicht während der Auswertung des Ausdrucks "x" auf der rechten Seite des Zuweisungsoperators "=".
Das ist falsch. Das Zuweisungsoperator hat eine Nebenwirkung, nämlich das Zuweisen an x.
 
@Tron
Mit deiner Beschreibung bin ich nicht einverstanden.

Zuweisungsoperatoren haben einen Effekt, das ist keine Nebenwirkung. Eine Nebenwirkung tritt erst dann ein, wenn zusätzliche Effekte auftreten.
 
Du kannst gerne nicht einverstanden sein. Nur gibt mit die C-Norm recht. Ich zitiere einen Satz aus der Beschreibung des Zuweisungsoperators: (Hervorhebung von mir)
ISO/IEC 9899:2011 6.5.16 Assignment operators schrieb:
The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

Aber schon die Definition von "side effect" bestätigt das schon: (Hervorhebung von mir)
5.1.2.3 Program execution schrieb:
Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations are all side effects.
 
Hallo,

vielen Dank für die Rückmeldungen.

Zum Thema "Was ist ein Seiteneffekt"?
Da ist der Fachausdruck Seiteneffekt vielleicht fehlleiten, deswegen findet man den zugehörigen Wikipediaartikel auch unter dem Begriff Wirkung_Informatik ( http://de.wikipedia.org/wiki/Wirkung_(Informatik)). Bei der Definition hat Tron in meinen Augen mit dem Versweis auf ISO/IEC9899:2011 recht, ich hatte ja auch schon den entsprechenden Abschnitt aus dem ANSI-Draft zitiert. Da hat sich seit 1989 also wenig geändert. ;)

Weiter habe ichseit gestern den Rationale for American Nationale Standard for Information Systems - Programming Language - C gefunden. Ein Dokument, das die Entscheidungen des Normierungsgremiums erläutert (online z.B. unter https://www.cs.technion.ac.il/users/yechiel/CS/C++draft/rationale.pdf oder http://www.lysator.liu.se/c/rat/title.html ).
Dort heißt es zum Thema Side effect auf Seite mit der Seitenzahl 48:
Some definitions: A side effect is a storage to any data object, or a read of a volatile object.
Und ein Object ist im ANSI-Draft (ok ich reiche eine URL dazu nach: http://flash-gordon.me.uk/ansi.c.txt) definiert
* Object --- a region of data storage in the execution environment,
the contents of which can represent values. Except for bit-fields,
objects are composed of contiguous sequences of one or more bytes, the
number, order, and encoding of which are either explicitly specified
or implementation-defined.
Nachdem der ANSI Rationale von storage und nicht modification spricht, kann man beruhigt davon ausgehen, dass die Zeile
Code:
x=x;
einen Seiteneffekt hat: Es wird ein Wert in der Variable x abgespeichert.

Keinen Seiteneffekt haben dagegen (außer dem Nullstatement) Zeilen wie
Code:
x<y;
x+1;
bei denen das berechnungsergebnis weggeworfen wird.

ciao
chaos
 
Das ist falsch. Das Zuweisungsoperator hat eine Nebenwirkung, nämlich das Zuweisen an x.

Und das ist richtig. Ich war bei meinen Betrachtungen auf den Ausdruck auf der rechten Seite der Zuweisung stehen geblieben. Die Zuweisung selbst ist ja auch wieder ein Ausdruck. Und damit kommt der Seiteneffekt...

Danke für die Korrektur. :)

Zuweisungsoperatoren haben einen Effekt, das ist keine Nebenwirkung. Eine Nebenwirkung tritt erst dann ein, wenn zusätzliche Effekte auftreten.

Es ist leichter zu erkennen, wenn du zwei Zuweisungen kombinierst:

Code:
x = y = 5;

Der Ausdruck

Code:
y = 5

wird aufgelöst zu 5. Der Nebeneffekt ist, dass y einen Wert zugewiesen bekommt. Dieser Ausdruck (5) wird dann x zugewiesen. Eigentlich gibt dieser Ausdruck (x = 5) dann auch 5 zurück, aber er wird verworfen weil ihn keiner abfragt. Nebeneffekt ist, dass x den Wert 5 erhält. So wird dann auch ein Schuh draus, hoffe ich.
 
Ich habe mir nicht alles durchgelesen, antworte mal aber trotzdem mal darauf:

Der Rückgabewert von x=x ist x und der Nebeneffekt ist, dass x x zugewiesen wird.
 
Zurück
Oben