Forum: Mikrocontroller und Digitale Elektronik fragezeichen operator may be undefined


von Mark (Gast)


Lesenswert?

Hallo,
bei der zeile
1
maincounter = (maincounter >= 250) ? 0 : maincounter++;
bekomme ich die Meldung:
operation on 'maincounter' may be undefined

wenn ich maincounter++ mit maincounter+1 ersetze, funktioniert es. Wieso 
wird ++ nicht erkannt?

von B. S. (bestucki)


Lesenswert?

Mark schrieb:
> wenn ich maincounter++ mit maincounter+1 ersetze, funktioniert es. Wieso
> wird ++ nicht erkannt?

Weil es nicht das Gleiche ist.

Mark schrieb:
> maincounter = (maincounter >= 250) ? 0 : maincounter++;

In Textform: Wenn maincounter grösser oder gleich 250 ist, liefere null 
und weise den gelieferten Wert maincounter zu. Ansonsten liefere 
maincounter, inkrementiere maincounter und weise den gelieferten Wert 
maincounter zu.


EDIT:
Wenn maincounter < 250 ist, steht da:
1
maincounter = maincounter++;
Das ist Unsinn und daher undefiniert.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Mark (Gast)

>maincounter = (maincounter >= 250) ? 0 : maincounter++;

Sowas sollte man lassen, das ist schlechter Stil.

https://www.mikrocontroller.net/articles/Strukturierte_Programmierung_auf_Mikrocontrollern#Benennung_von_Variablen.2C_Makros.2C_Nutzung_von_Anweisungen

Was spricht gegen ein simples

1
if (++maincounter >= 250) maincounter=0;

?

von Falk B. (falk)


Lesenswert?

@Be Stucki (bestucki)

>maincounter = maincounter++;

>Das ist Unsinn und daher undefiniert.

Naja, in C sind ganz andere Sachen definiert. Auch das hier sollte 
gültiges C sein, denn maincounter wird sich selber wieder zugewiesen und 
DANACH nach einmal incrementiert. Ist zwar Käse, geht aber.
So oder so ist ein normales if() besser.

von Dussel (Gast)


Lesenswert?

Falk B. schrieb:
> Naja, in C sind ganz andere Sachen definiert. Auch das hier sollte
> gültiges C sein, denn maincounter wird sich selber wieder zugewiesen und
> DANACH nach einmal incrementiert.
Nein, das ist nicht definiert. Der Ausdruck kann verursachen, was er 
will.

von Rolf M. (rmagnus)


Lesenswert?

Falk B. schrieb:
> @Be Stucki (bestucki)
>
>>maincounter = maincounter++;
>
>>Das ist Unsinn und daher undefiniert.
>
> Naja, in C sind ganz andere Sachen definiert. Auch das hier sollte
> gültiges C sein,

Syntaktisch ja. Das Ergebnis der Operation ist aber undefiniert, so wie 
es das in C immer ist, wenn ein Objekt mehr als einmal geschrieben wird, 
ohne dass ein Sequenzpunkt dazwischen liegt.

> denn maincounter wird sich selber wieder zugewiesen und DANACH nach
> einmal incrementiert.

Sagt wer?

von B. S. (bestucki)


Lesenswert?

Falk B. schrieb:
> Naja, in C sind ganz andere Sachen definiert. Auch das hier sollte
> gültiges C sein, denn maincounter wird sich selber wieder zugewiesen und
> DANACH nach einmal incrementiert.

Ist nicht definiert. Aus dem Standard:
> The value computation of the result is sequenced before the side effect
> of updating the stored value of the operand. With respect to an
> indeterminately-sequenced function call, the operation of postfix ++
> is a single evaluation.

Das "indeterminately-sequenced function call" ist das Wichtige dabei. Es 
ist nicht definiert, wann der Wert geschrieben wird, daher ist der 
gesamte Ausdruck undefiniert.


Falk B. schrieb:
> @Mark (Gast)
>>maincounter = (maincounter >= 250) ? 0 : maincounter++;
> Sowas sollte man lassen, das ist schlechter Stil.
> 
https://www.mikrocontroller.net/articles/Strukturierte_Programmierung_auf_Mikrocontrollern#Benennung_von_Variablen.2C_Makros.2C_Nutzung_von_Anweisungen
>
> Was spricht gegen ein simples
> if (++maincounter >= 250) maincounter=0;

In diesem Fall wäre ein if-else besser gewesen. Ich würde aber den 
?-Operator nicht grundsätzlich als schlechten Stil verteufeln. Einfache 
Ausdrücke kann man damit übersichtlich in eine kurze Zeile schreiben. 
Ich empfinde es übrigens als schlechten Stil, keine geschweiften 
Klammern zu verwenden.

von W.S. (Gast)


Lesenswert?

Falk B. schrieb:
> if (++maincounter >= 250) maincounter=0;

C-Fans neigen gar sehr, immer alles zusammenziehen zu wollen, egal was 
sie sich an Un-Lesbarkeit oder Bugs dabei einhandeln. Wahrscheinlich 
kann man solches Fehlverhalten nicht abgewöhnen.

Bei mir wäre das:
++maincounter;
if (maincounter>=250) maincounter=0;

So ist es sauber, sieht auch sauber aus, liest sich einfach und ist 
ohnehin vom Compiler optimierbar. Aber der TO will vermutlich nicht 
biederen Quelltext schreiben, sondern Heldentaten vollbringen - egal, 
wieviel Zeit es ihn bereits gekostet hat, um hier nachzufragen, weil der 
Compiler ihn angeschnarrt hat und er es selber nicht gesehen hat. In 
dieser Zeit hätte er es zehnmal so hinschreiben können wie ich.

W.S.

von Rolf M. (rmagnus)


Lesenswert?

Lothar M. schrieb im Beitrag #4651358:
> Be S. schrieb:
>> Das ist Unsinn
> Das ja.
>> und daher undefiniert.
> Mitnichten.

Die Wiederholung macht es nicht richtiger.

> Es ist recht genau definert, was da in welcher Reihenfolge
> passiert,

Nein! Die Reihenfolge ist undefiniert! Was überhaupt da passiert, ist 
undefiniert! Das gesamte Verhalten ist undefiniert!

Lothar M. schrieb im Beitrag #4651358:
> Ergebnis: http://codepad.org/iZpIGHGO

Das ist ein mögliches Ergebnis. Die Abwesenheit von undefiniertem 
Verhalten belegt das aber nicht.

W.S. schrieb:
> Bei mir wäre das:
> ++maincounter;
> if (maincounter>=250) maincounter=0;

Das ist aber was anderes. Der TE prüft nämlich vor dem Inkrementieren 
den Wert, du erst danach.
Daher also eher:
1
if (maincounter>=250)
2
    maincounter=0;
3
else
4
    maincounter++;

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@W.S. (Gast)

>> if (++maincounter >= 250) maincounter=0;

>C-Fans neigen gar sehr, immer alles zusammenziehen zu wollen, egal was
>sie sich an Un-Lesbarkeit oder Bugs dabei einhandeln. Wahrscheinlich
>kann man solches Fehlverhalten nicht abgewöhnen.

Quark, es war nur ein Beispiel, wie man es per if() machen kann.

>Bei mir wäre das:
>++maincounter;
>if (maincounter>=250) maincounter=0;

Wenn schon "schön", dann so.

1
maincounter++;
2
if (maincounter >= 250) {
3
  maincounter=0;
4
}

So schreib ich es im Normalfall auch! Hier hab ich es halt mal nicht 
gemacht. Auch ich bin ein Anhänger der "if() immer mit 
Klammern"-Schreibweise.

von Rolf M. (rmagnus)


Lesenswert?

Falk B. schrieb:
> Auch ich bin ein Anhänger der "if() immer mit Klammern"-Schreibweise.

So unterschiedlich können die Geschmäcker sein. Ich bin kein besonderer 
Anhänger dieser Schreibweise, dafür aber Anhänger der 
"öffnende-und-schließende-Klammer-in-der-selben-Spalte"-Schreibweise. 
Dementsprechend gefällt es mir so, wie du es schreibst, überhaupt nicht. 
Ich finde das unübersichtlich.

von Falk B. (falk)


Lesenswert?

@ Rolf Magnus (rmagnus)

>> Auch ich bin ein Anhänger der "if() immer mit Klammern"-Schreibweise.

>So unterschiedlich können die Geschmäcker sein.

Nicht wahr ;-)

> Ich bin kein besonderer
>Anhänger dieser Schreibweise, dafür aber Anhänger der
>"öffnende-und-schließende-Klammer-in-der-selben-Spalte"-Schreibweise.

Also so.
1
maincounter++;
2
if (maincounter >= 250)
3
{
4
  maincounter=0;
5
}

Kann man machen, ist halt eine Zeile mehr, die bei längeren Funktionen 
>1 Bildschirmseite ggf. etwas weniger Überblick zulassen. Aber darüber 
will ich nicht philosophieren! Es ist Geschmackssache!

>Dementsprechend gefällt es mir so, wie du es schreibst, überhaupt nicht.
>Ich finde das unübersichtlich.

Ich halte mich da an die Empfehlungen von iD Software. Und wenn DIE 
Jungs das so machen, kann das nicht so schlecht sein ;-)

Abschnitt Spacing

http://kotaku.com/5975610/the-exceptional-beauty-of-doom-3s-source-code


ftp://ftp.idsoftware.com/idstuff/doom3/source/CodeStyleConventions.doc

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Rolf M. schrieb:
> Das gesamte Verhalten ist undefiniert!
Wo ist definiert, dass "i=i++" undefiniert ist?
Mal nachgesehen: im "Standard".
Weil nämlich sowohl "i =" wie auch "i++" dem "i" in der gleichen Zeile 
einen neuen Wert zuweisen, ist das nicht erlaubt...

Eigentlich ist auch beim Nachdenken klar, dass das mit dem Postinkrement 
und der Zuweisung schief gehen muss. Denn das Gleichheitszeichen 
bedeutet ja: "zuweisen, wenn der Term rechts vom Gleichheitszeichen 
ausgewertet ist" und der Posinkrement bedeutet: "Inkrementieren, wenn 
die Zeile abgearbeitet ist"...

Ich hätte da sowieso so geschrieben:  i>=250 ? 0:i+1;
Nochmal Glück gehabt... ;-)

: Bearbeitet durch Moderator
von Yalu X. (yalu) (Moderator)


Lesenswert?

Lothar M. schrieb:
> der Posinkrement bedeutet: "Inkrementieren, wenn
> die Zeile abgearbeitet ist"...

Nicht ganz: Er bedeutet, dass die Variable frühestens nach dem Lesen
ihres Inhalts und spätestens beim nächsten Sequence-Point (in diesem
Fall also vor Beginn der Abarbeitung der nächsten Zeile) inkrementiert
wird.

Innerhalb dieses Intervalls darf sich der Compiler einen beliebigen
Zeitpunkt für die Inkrementierung der Variable aussuchen. Sie könnte in
diesem Fall also wahlweise vor oder nach der Zuweisung geschehen,
was zu unterschiedlichen Ergebnissen führen würde.

Um die Verwirrung nicht ins Grenzenlose wachsen zu lassen, werden solche
Konstrukte einfach komplett verboten.

Lothar M. schrieb:
> Ich hätte da sowieso so geschrieben:  i>=250 ? 0:i+1;

Das wollte der TO vermutlich ebenfalls, nur war ihm der Unterschied
zwischen x++ und x+1 wohl nicht ganz klar.

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Yalu X. schrieb:
> Innerhalb dieses Intervalls darf sich der Compiler einen beliebigen
> Zeitpunkt für die Inkrementierung der Variable aussuchen. Sie könnte in
> diesem Fall also wahlweise vor oder nach der Zuweisung geschehen,
> was zu unterschiedlichen Ergebnissen führen würde.

 Das ist C mit seinen idiotischen oder nicht vorhandenen Regeln.

 Es darf nichts zugewiesen werden, solange der Ausdruck rechts
 nicht komplett abgearbeitet ist, Reihenfolge ist in diesem Fall
 absolut unwichtig.
 Es wird immer der Eingangszustand genommen und nicht irgendwelche
 Zwischenergebnise.

 Links = variable (momentaner Zustand und nicht irgendein beliebiges).
 Rechts = variable + 1 oder variable++

 Resultat = Rechts (und es ist immer variable+1).

 Das kann nur in C undefined sein.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Was die Sache hier etwas interessanter gestaltet: ? ist ein sequence 
point, bezogen auf die Auswertung links und rechts davon. Nützt aber 
nichts, weil dahinter wie schon beschrieben in einem Zweig
  i = i++;
übrig bleibt, und da ist keiner dazwischen. Anders wärs bei
  i = (i++ >= 100) ? 0 : i;
auch wenn das Code zum Haare ausraufen ist.

: Bearbeitet durch User
von Sebi (Gast)


Lesenswert?

Marc V. schrieb:
> Resultat = Rechts (und es ist immer variable+1).

Nein! Das ist doch der Witz von Postincrement. Wenn man es mit 
verschiedenen Variablen macht:
1
j = i++;
Dann ist j nach dieser Zeile natürlich der Wert von i VOR dem 
incrementieren.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Sebi schrieb:
> Dann ist j nach dieser Zeile natürlich der Wert von i VOR dem
> incrementieren.

 Ja.
 Der Idiot bin ich, natürlich.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Hmmm.

 Beim Fragezeichen habe ich den Vergleich übersehen und der kann
 natürlich so oder so ausfallen, aber warum sollte folgendes auch
 undefined sein:
1
 maincounter = ++maincounter;

 Es kann so berechnet werden (mit zwischenspeichern):
1
 {tmp1 = maincounter}  =  {Res = maincounter : inc(Res) : maincounter = Res}
2
 {tmp1 = Res}
3
 {maincounter = tmp1}
 Ohne zwischenspeichern LEFT:
1
  maincounter  =  {Res = maincounter : inc(Res) : maincounter = Res}
2
 {maincounter = Res}
 Ohne zwischenspeichern RIGHT):
1
 {tmp1 = maincounter}  =  {inc(maincounter)} // oder: maincounter + 1
2
 {tmp1 = maincounter}
3
 {maincounter = tmp1}
 Und selbst wenn so gerechnet wird (ohne überhaupt zwischenzuspeichern):
1
  maincounter   =  {inc(maincounter)}        // oder: maincounter + 1
2
 {maincounter = maincounter}

 Es ist PRE increment, ohne Vergleich, da kann es auch keine race
 condition geben.

 Und selbst dies kann nicht undefined sein:
1
 maincounter = maincounter++;
 Denn bei:
1
 maincounter = maincounter+1;
 meckert der Compiler überhaupt nicht, obwohl kein Unterschied
 besteht.

 Klar, im zweiten Fall wird ein Wert zugewiesen und im ersten
 Fall direkt an der Variable rumgeschraubt, aber trotzdem...

 Warnung bei so etwas kann ich verstehen:
1
  a[i++] = i++;

 aber in den obigen zwei Fällen nicht (auch wenn alle 3 Blödsinn sind).

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

Marc V. schrieb:
> Beim Fragezeichen habe ich den Vergleich übersehen und der kann
> natürlich so oder so ausfallen, aber warum sollte folgendes auch
> undefined sein:
> maincounter = ++maincounter;

Das ist ebenfals undefiniert, denn ++maincounter ist äquivalent zu 
maincounter+=1. Also:
1
maincounter = ++maincounter;
2
maincounter = maincounter += 1;
3
maincounter = maincounter = maincounter + 1;

Alles undefiniert. Merke: Sobald zwischen zwei sequence points mehr als 
einmal schreibend auf eine Variable zugegriffen wird, wird undefiniertes 
Verhalten erzeugt. Eine Zuweisung ist kein sequence point.


Marc V. schrieb:
> Und selbst dies kann nicht undefined sein:
> maincounter = maincounter++;
> Denn bei:
> maincounter = maincounter+1;
> meckert der Compiler überhaupt nicht, obwohl kein Unterschied besteht.

Natürlich besteht ein Unterschied. Beim Ersten wird zwei Mal in 
undefinierter Reihenfolge schreibend auf maincounter zugegriffen. Beim 
Zweiten wird ein Wert berechnet und zugewiesen, also nur ein 
Schreibzugriff.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Be S. schrieb:
> Merke: Sobald zwischen zwei sequence points mehr als
> einmal schreibend auf eine Variable zugegriffen wird, wird undefiniertes
> Verhalten erzeugt.

Alternativ auch, wenn zwischen zwei Sequenzpunkten die Variable 
geschrieben wird und auch gelesen, ohne dass dieser Lesezugriff dazu 
dient, den Wert für den Schreibzugriff zu ermitteln.
Beispiel:
1
x = variable * variable++;
Auch das ist undefiniert, da variable per Operator ++ beschrieben wird, 
aber links von der Multiplikation zu einem anderen Zweck als für den 
Operator++ auch gelesen wird.

Marc V. schrieb:
> Und selbst dies kann nicht undefined sein:
> maincounter = maincounter++;
>  Denn bei:
> maincounter = maincounter+1;
>  meckert der Compiler überhaupt nicht, obwohl kein Unterschied
>  besteht.
>
>  Klar, im zweiten Fall wird ein Wert zugewiesen und im ersten
>  Fall direkt an der Variable rumgeschraubt, aber trotzdem...

Nein. Im zweiten Fall wird zugewiesen und "direkt an der Variable 
rumgeschraubt".

von Falk B. (falk)


Lesenswert?

Also lange Rede, kurzer Sinn. Man sollte mit den C-typischen Stunts x++ 
etc. eher sparsam umgehen und diese Sachen lieber eindeutig und leicht 
lesbar in getrennte Anweisungen schreiben.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Be S. schrieb:
> Natürlich besteht ein Unterschied. Beim Ersten wird zwei Mal in
> undefinierter Reihenfolge schreibend auf maincounter zugegriffen. Beim
> Zweiten wird ein Wert berechnet und zugewiesen, also nur ein
> Schreibzugriff.

Marc V. schrieb:
> Klar, im zweiten Fall wird ein Wert zugewiesen und im ersten
>  Fall direkt an der Variable rumgeschraubt, aber trotzdem...

 Das habe ich doch auch geschrieben, oder ?

 Und die Reihenfolge ist gerade in diesem Fall absolut unwichtig.
 Es muss auf jeden Fall zuerst {mainconter = maincounter} ausgeführt
 werden und danach Rechts erhöht werden.
 Absolut kein Unterschied und vor allem kein undefiniertes Resultat.

von Paul B. (paul_baumann)


Lesenswert?

Dieser Thread müßte eigentlich als Link in das C-Tutorial aufgenommen 
werden. Warum? Um die Leute vor dem zu warnen, was sie sich aufhalsen 
wollen.

MfG Paul

von B. S. (bestucki)


Lesenswert?

Marc V. schrieb:
> Es muss auf jeden Fall zuerst {mainconter = maincounter} ausgeführt
> werden und danach Rechts erhöht werden.

Der Standard sieht das aber anders und nur der zählt.


Marc V. schrieb:
> Absolut kein Unterschied und vor allem kein undefiniertes Resultat.

Wenn das so ist, dann erkläre mir bitte folgendes Verhalten:
1
#include <stdio.h>
2
3
4
int main(void){
5
  unsigned int x = 5;
6
  x = x++;
7
  printf("%u\n", x);
8
  x = x + 1;
9
  printf("%u\n", x);
10
  
11
  return 0;
12
}

Ausgabe:
1
5
2
6


Kompiliert mit GCC 4.9.3 mit -O3

von Falk B. (falk)


Lesenswert?

@ Paul Baumann (paul_baumann)

>Dieser Thread müßte eigentlich als Link in das C-Tutorial aufgenommen
>werden.

Das kannst du doch machen.

> Warum? Um die Leute vor dem zu warnen, was sie sich aufhalsen
>wollen.

In jedem PRAXISNAHEN C-Kurs wird vor solchen Sachen gewarnt und jeder 
vernünftige Mensch wird davon auch die Finger lassen. C ist nicht 
perfekt, aber nun mal ein weit verbreiteter Standard.

von Falk B. (falk)


Lesenswert?

@  Be Stucki (bestucki)

>Kompiliert mit GCC 4.9.3 mit -O3

Gab es Warnungen?

von B. S. (bestucki)


Lesenswert?

Falk B. schrieb:
> @  Be Stucki (bestucki)
>
>>Kompiliert mit GCC 4.9.3 mit -O3
>
> Gab es Warnungen?

Ja:
1
main.c 6 warning: operation on ‘x’ may be undefined [-Wsequence-point]

von Dussel (Gast)


Lesenswert?

Falk B. schrieb:
> Man sollte mit den C-typischen Stunts x++
> etc. eher sparsam umgehen und diese Sachen lieber eindeutig und leicht
> lesbar in getrennte Anweisungen schreiben.
Finde ich nicht. Man sollte ein bisschen nachdenken. Was soll x=x++ 
machen? x um eins erhöhen? Dann schreibt man x++. Sonst fällt mir keine 
sinnvolle Anweisung ein, die man mit dem Ausdruck meinen könnte.

x=x++ ist in C einfach nicht definiert. Wenn das Programm mit der 
Anweisung die dritte Wurzel aus x zieht und danach das Universum 
zerstört, ist das absolut standardgemäß (allerdings muss ich zugeben, 
dass ich nicht weiß, ob der Standard nicht an anderer Stelle die 
Zerstörung des Universums verbietet :D).

Es steht jedem frei, eine neue Programmiersprache zu entwickeln, in der 
das Ergebnis von x=x++ und zum Beispiel y=x/0 genau definiert ist. Eine 
solche Sprache ist C aber eben nicht.

Nebenbei gesagt, habe ich auch nichts gegen sowas wie
x=x<Schwellwert?-1:1;
Das ist kurz und eindeutig.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Rolf M. schrieb:
>>  Klar, im zweiten Fall wird ein Wert zugewiesen und im ersten
>>  Fall direkt an der Variable rumgeschraubt, aber trotzdem...
>
> Nein. Im zweiten Fall wird zugewiesen und "direkt an der Variable
> rumgeschraubt".

 Wie das ?
 Zuweisung ist "=".
 Bei
1
 maincounter+1;
 wird der maincounter nur gelesen.

 und mit:
1
 maincounter =
 wird der neue Wert zugewiesen.
 Da wird zwischendurch nichts an der Variable verändert.

von Falk B. (falk)


Lesenswert?

@Dussel (Gast)

>> Man sollte mit den C-typischen Stunts x++
>> etc. eher sparsam umgehen und diese Sachen lieber eindeutig und leicht
>> lesbar in getrennte Anweisungen schreiben.

>Finde ich nicht. Man sollte ein bisschen nachdenken.

Darum geht es gar nicht. Quelltext soll kein Logikrätsel sein sondern 
möglicht gut und einfach lesbar bzw. zu verstehen.

> Was soll x=x++
>machen? x um eins erhöhen? Dann schreibt man x++. Sonst fällt mir keine
>sinnvolle Anweisung ein, die man mit dem Ausdruck meinen könnte.

Darum geht es gar nicht.

>Nebenbei gesagt, habe ich auch nichts gegen sowas wie
>x=x<Schwellwert?-1:1;
>Das ist kurz und eindeutig.

Für so einen Müll gehört der Verursacher geteert und gefedert!!!
Das ist autistische Hackerscheiße!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Be S. schrieb:
> Wenn das so ist, dann erkläre mir bitte folgendes Verhalten:

 Wieso ich ?

 Habe ich GCC geschrieben ?
 Bin ich für dieses Verhalten verantwortlich ?

 Was ist an dieser Zuweisung unklar (ausser, dass es Blödsinn ist) ?
1
  x = x++;

 Was kann da falsch gerechnet werden und undefiniert sein ?

 Wie man auch rechnet - zuerst rechts, dann links, dann wieder rechts
 oder andersrum - es ergibt immer x+1.
 Dass es beim GCC nicht so abläuft wie es ablaufen soll, ist bestimmt
 nicht mein Fehler.

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

Dussel schrieb:
> x=x++ ist in C einfach nicht definiert. Wenn das Programm mit der
> Anweisung die dritte Wurzel aus x zieht und danach das Universum
> zerstört, ist das absolut standardgemäß (allerdings muss ich zugeben,
> dass ich nicht weiß, ob der Standard nicht an anderer Stelle die
> Zerstörung des Universums verbietet :D).

Der Standard sagt dazu:
> undefined behavior
> behavior, upon use of a nonportable or erroneous program construct or
> of erroneous data, for which this International Standard imposes no
> requirements
> NOTE Possible undefined behavior ranges from ignoring the situation
> completely with unpredictable results, to behaving during translation
> or program execution in a documented manner characteristic of the
> environment (with or without the issuance of a diagnostic message), to
> terminating a translation or execution (with the issuance of a
> diagnostic message).

Also: Entweder wird die Sache mit unvorhersehbarem Resultat ignoriert, 
verhält sich nach Dokumentation oder das Programm wird beendet. Du 
müsstest also in der Compilerdokumentation nachsehen, ob das Universum 
möglicherweise zerstört wird oder nicht.

von B. S. (bestucki)


Lesenswert?

Marc V. schrieb:
> Dass es beim GCC nicht so abläuft wie es ablaufen soll, ist bestimmt
>  nicht mein Fehler.

Es läuft so ab, wie es soll. Lese und verstehe obige Beiträge und den 
Standard. Nur weil du denkst, es sei so wie du denkst, heisst das noch 
lange nicht, dass es auch wirklich so ist.

von Dussel (Gast)


Lesenswert?

Falk B. schrieb:
> Für so einen Müll gehört der Verursacher geteert und gefedert!!!
> Das ist autistische Hackerscheiße!
Ok, ich hatte dich zwischenzeitlich wieder als etwas besser 
eingeschätzt, aber damit hast du dich dann doch wieder als unfähiger 
Idiot zu erkennen gegeben.
Schade.

von W.S. (Gast)


Lesenswert?

Falk B. schrieb:
> Ich halte mich da an die Empfehlungen von iD Software. Und wenn DIE
> Jungs das so machen, kann das nicht so schlecht sein ;-)

Das ist Dressur, also es genau so machen wie man es irgend wann mal 
eingetrichtert bekommen hat.

OK, es kommt in diesem Falle ja nichts direkt Falsches dabei heraus.

Trotzdem ist es schlichtweg logischer,

if (bedingung) Statement;

zu schreiben. Und wenn das Statement eben nur ein einfaches Statement 
ist, dann gehört darum keine Block-Klammer, denn es ist ja kein Block, 
den man zusammenfassen müßte.

Auch überflüssiger Zinnober, der zwar nicht zu Fehlern führt, aber 
dennoch eben überflüssig ist, ist ÜBERFLÜSSIG - und irgendwann 
verwirrend. Das gilt auch für die üble Angewohnheit, Block-Eröffnungen 
auf das davorliegende Zeilenende zu verfrachten. Jaja, auch wenn ganz 
viele Leute das genau so machen, eben weil sie es andressiert bekommen 
haben und sich seitdem keinen eigenen Gedanken darüber gemacht haben.

Kurzum, die Schreibweise, wo Blockeröffnung und Blockende in der 
gleichen Spalte stehen, ist sauberer, da sie dem menschlichen Leser das 
visuelle Erfassen der Struktur erleichtern. In diesem Falle

if (bedingung)
{ ...
  ...
}

Dem Compiler hingegen ist das alles wurscht.

W.S.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Be S. schrieb:
> Es läuft so ab, wie es soll. Lese und verstehe obige Beiträge und den
> Standard. Nur weil du denkst, es sei so wie du denkst, heisst das noch
> lange nicht, dass es auch wirklich so ist.

 Wenn es um verstehen geht, wollte ich dir gerade dasselbe empfehlen.

 Wenn es um Standard geht, ist es eine ganz andere Sache - da kann
 auch drin stehen, dass a + 3 immer 9 ergibt, unabhängig vom Wert der
 Variable a.
 Wenn ich diese Sprache benutzen will, muss ich damit leben.
 Genauso ist es mit a = a++;

 Ob das aber einen Sinn ergibt, ist wiederum eine ganz andere Sache.

 Es gab mal (früher) eine Story wie und warum C überhaupt entstanden
 ist. Ich glaube immer mehr, dass diese wahr ist...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

W.S. schrieb:
> Kurzum, die Schreibweise, wo Blockeröffnung und Blockende in der
> gleichen Spalte stehen, ist sauberer, da sie dem menschlichen Leser das
> visuelle Erfassen der Struktur erleichtern.

 Selbstverständlich ist es so logischer und vor allem übersichtlicher.
 Aber irgendwie sieht es nach Anfänger aus und da alle die in C
 programmieren (meistens erfolglos) sich für grosse Experten halten,
 ist es verpönt.

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

Marc V. schrieb:
> Wenn es um verstehen geht, wollte ich dir gerade dasselbe empfehlen.

Ich verstehe deine Einwände, dass man die Operation in solch simplen 
Fällen auch hätte definieren können. Macht aber keinen Sinn, denn dann 
hätte man konsequenterweise auch
1
x = x++ + ++x;
und
1
y[x++] = ++x;
definieren müssen.


Marc V. schrieb:
> Und selbst dies kann nicht undefined sein:
> maincounter = maincounter++;
> Denn bei:
> maincounter = maincounter+1;
> meckert der Compiler überhaupt nicht, obwohl kein Unterschied besteht.

Marc V. schrieb:
> Absolut kein Unterschied und vor allem kein undefiniertes Resultat.

Diese beiden Aussagen lassen darauf schliessen, dass das Resultat nicht 
undefiniert sei und beide Beispiel äquivalent sein würden. Dies ist aber 
nicht korrekt, deswegen meine Einwände.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Be S. schrieb:
> maincounter = ++maincounter;
> maincounter = maincounter += 1;
> maincounter = maincounter = maincounter + 1;
>
> Alles undefiniert.

In diesem Fall bin ich mir in C99 nicht so sicher.

Das C99 Rationale drückt sich nämlich in 6.5.16 ein wenig anders aus:

"The storage assignment need not take place until the next sequence 
point. As a consequence, a straightforward syntactic test for ambiguous 
expressions can be stated. Some definitions: A side effect is a storage 
to any data object [...]. An ambiguous expression is one whose value 
depends upon the order in which side effects are evaluated. [...]"

`whose value depends upon the order in which side effects are 
evaluated´. Es ist also nicht entscheidend, wie oft geschrieben wird, 
sondern ob sich durch eine andere Reihenfolge etwas ändern kann. Was 
hier nicht der Fall ist.

"A sequenced expression is one whose major operator defines a sequence 
point: comma, &&, ||, or conditional operator; an unsequenced expression 
is any other. We can then say that an unsequenced expression may be 
ambiguous [..] if more than one operand contains an lvalue referencing 
the same object and one or more operands specify a side effect to that 
object."

`may be ambiguous´. Kann zweideutig sein, muss aber nicht.

(Weggelassen habe ich Aussagen über bestimmte Funktionsaufrufe und 
volatile Zugriffe)

Aus (1)

> Sobald zwischen zwei sequence points mehr als
> einmal schreibend auf eine Variable zugegriffen wird, wird undefiniertes
> Verhalten erzeugt.

wird diesem Text zufolge also (2)

> Sobald zwischen zwei sequence points mehr als
> einmal schreibend auf eine Variable zugegriffen wird, kann undefiniertes
> Verhalten erzeugt werden.

PS: Dass man so einen Stuss nicht schreiben sollte ist klar. Also dass 
man sich an (1) halten sollte, auch wenn formal (2) korrekt ist.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Be S. schrieb:
> hätte man konsequenterweise auch
1
 x = x++ + ++x;
> definieren müssen.

 Nein, da stimmt das Resultat immer, im Gegensatz zu:
1
 y = x++ + ++x;
 wo es sehr wohl ein Unterschied macht (z.B. beim Überlauf).

und
1
 y[x++] = ++x;
> definieren müssen.

 Selbst das muss nicht undefiniert sein, (obwohl es Blödsinn ist),
 weil Rechts ein PRE increment steht, also ist das Resultat:
1
 x = 5;
2
 y[x++] = ++x;
3
4
 1:  y[x++] = 6;
5
 2:  y[6] = 6;
6
 3:  x = 7;

von (prx) A. K. (prx)


Lesenswert?

Be S. schrieb:
> müsstest also in der Compilerdokumentation nachsehen, ob das Universum
> möglicherweise zerstört wird oder nicht.

Das sollte bei "implementation defined" helfen, hilft vielleicht auch 
bei "unspecified", nicht aber bei "undefined".

von Falk B. (falk)


Lesenswert?

@ W.S. (Gast)

>> Ich halte mich da an die Empfehlungen von iD Software. Und wenn DIE
>> Jungs das so machen, kann das nicht so schlecht sein ;-)

>Das ist Dressur, also es genau so machen wie man es irgend wann mal
>eingetrichtert bekommen hat.

Blödsinn^3! Die Jungs von ID Software haben wir kaum was eingetrichtert. 
Sie haben IHRE Sicht der Dinge dragestellt, ich hab sie angesehen und 
drüber nachgedacht und am Ende fand ich fast alles logisch, schlüssig 
und sinnvoll!

>Trotzdem ist es schlichtweg logischer,

>if (bedingung) Statement;

>zu schreiben. Und wenn das Statement eben nur ein einfaches Statement
>ist, dann gehört darum keine Block-Klammer, denn es ist ja kein Block,
>den man zusammenfassen müßte.

NEIN!!! Warum das so ist, steht in den Links!

>Auch überflüssiger Zinnober, der zwar nicht zu Fehlern führt, aber
>dennoch eben überflüssig ist, ist ÜBERFLÜSSIG - und irgendwann
>verwirrend.

Du hast es nicht verstanden.

> Das gilt auch für die üble Angewohnheit, Block-Eröffnungen
>auf das davorliegende Zeilenende zu verfrachten.

Auch das wurde begründet!!!

>Jaja, auch wenn ganz
>viele Leute das genau so machen, eben weil sie es andressiert bekommen

Quark.

>haben und sich seitdem keinen eigenen Gedanken darüber gemacht haben.

Das GEGENTEIL ist der Fall!

>Kurzum, die Schreibweise, wo Blockeröffnung und Blockende in der
>gleichen Spalte stehen, ist sauberer,

Hast du dein Pascal-Martyrium noch nicht überwunden ? ;-)

> da sie dem menschlichen Leser das
>visuelle Erfassen der Struktur erleichtern.

Die andere Schreibweise auch, dennjedes if() braucht eine schließende 
Klammer, die öffnende steht am Zeilenende.

>Dem Compiler hingegen ist das alles wurscht.

Darum geht es keine Sekunde. Dann dann könnte man gleich alles in eine 
Zeile schreiben. Thema verfehlt!

von Falk B. (falk)


Lesenswert?

@Be Stucki (bestucki)

>> Wenn es um verstehen geht, wollte ich dir gerade dasselbe empfehlen.

>Ich verstehe deine Einwände, dass man die Operation in solch simplen
>Fällen auch hätte definieren können. Macht aber keinen Sinn, denn dann
>hätte man konsequenterweise auch

>x = x++ + ++x;

>und

>y[x++] = ++x;

>definieren müssen.

Eben. Die Philosophie von C, aktive (schreibende) Operationen mit 
logischen Ausdrücken zu vermischen ist so oder so nicht ganz koscher. 
Das sollte man SEHR zurückhaltend nutzen. Wenn man erst ne Minute über 
einen Ausdruck nachdenken oder gar die Operatorenreihenfolge im Buch 
nachschlagen muss, ist es meist zu komplex!

von Falk B. (falk)


Lesenswert?

@A. K. (prx)

>`may be ambiguous´. Kann zweideutig sein, muss aber nicht.

>(Weggelassen habe ich Aussagen über bestimmte Funktionsaufrufe und
>volatile Zugriffe)

Ob es einer Programmiersprach gut bekommt, wenn sich deren 
Definition/Standard mehr und mehr wie ein juristisches Machwerk lies? 
Was verliert man denn, wenn man diese logischen Spitzfindigkeiten 
einfach verbietet?

KISS!!

von (prx) A. K. (prx)


Lesenswert?

Falk B. schrieb:
>Ob es einer Programmiersprach gut bekommt, wenn sich deren
> Definition/Standard mehr und mehr wie ein juristisches Machwerk lies?

K&R liess einiges in der Schwebe, was der Sprache nicht gut tat.

> Was verliert man denn, wenn man diese logischen Spitzfindigkeiten
> einfach verbietet?

Der zitierte Text stammt nicht einmal aus dem Standard selbst, sondern 
aus den Erklärungen dazu. ;-)

> KISS!!

Ist der Fall, denn im Grunde ist es wirklich einfach:
Verboten ist Zweideutigkeit im Ergebnis. Der Rest folgt daraus.

von Rolf M. (rmagnus)


Lesenswert?

Marc V. schrieb:
> Rolf M. schrieb:
>>>  Klar, im zweiten Fall wird ein Wert zugewiesen und im ersten
>>>  Fall direkt an der Variable rumgeschraubt, aber trotzdem...
>>
>> Nein. Im zweiten Fall wird zugewiesen und "direkt an der Variable
>> rumgeschraubt".
>
>  Wie das ?

Hab mich verschrieben. Ich meinte den ersten Fall, nicht den zweiten, 
also

> maincounter = maincounter++;

Falk B. schrieb:
>> Was soll x=x++
>>machen? x um eins erhöhen? Dann schreibt man x++. Sonst fällt mir keine
>>sinnvolle Anweisung ein, die man mit dem Ausdruck meinen könnte.
>
> Darum geht es gar nicht.

Worum dann? Hier beschweren sich Leute, dass es unsinnige Ausdrücke 
gibt, die in C undefiniert sind.

Marc V. schrieb:
> Was ist an dieser Zuweisung unklar (ausser, dass es Blödsinn ist) ?  x =
> x++;
>
>  Was kann da falsch gerechnet werden und undefiniert sein ?

"Falsch gerechnet" werden kann da quasi per Definition nicht, denn 
undefiniertes Verhalten heißt, dass jedes beliebige Ergebnis richtig 
ist.

>  Wie man auch rechnet - zuerst rechts, dann links, dann wieder rechts
>  oder andersrum - es ergibt immer x+1.

Es kann auch eine "trap" ergeben, wenn der Prozessor das x++ und das x = 
... paralellisiert und dann einen Konflikt finden und das Programm 
terminiert. Das ganze wurde ja nicht für undefiniert erklärt, weil man 
keinen Bock hatte, es zu definieren, sondern um dem Compiler die Arbeit 
zu erleichtern. Man muss dabei auch im Hinterkopf behalten, dass C in 
den 70ern entstanden ist, als Compiler noch nicht so hochkomplex waren 
wie heute und auch auf Rechnern mit ein paar kB RAM laufen mussten. Der 
Optimizer oder auch der nicht optimierende Compiler muss sich zwischen 
zwei Sequenzpunkten nicht darum kümmern, ob es einen Sinn ergibt, wenn 
Sachen parallelisiert oder umsortiert werden oder was auch immer 
rauskommt.

>  Dass es beim GCC nicht so abläuft wie es ablaufen soll, ist bestimmt
>  nicht mein Fehler.

Es läuft so ab, wie es ablaufen soll. Dein Fehler ist, dass du falsche 
Erwartungen an das Ergebnis hast.

Marc V. schrieb:
> und y[x++] = ++x;
>> definieren müssen.
>
>  Selbst das muss nicht undefiniert sein, (obwohl es Blödsinn ist),
>  weil Rechts ein PRE increment steht, also ist das Resultat:
>  x = 5;
>  y[x++] = ++x;
>
>  1:  y[x++] = 6;
>  2:  y[6] = 6;
>  3:  x = 7;

Damit legst du an einigen Stellen eine bestimmte Reihenfolge fest, wo 
man in C bewusst dem Compiler die Freiheit gelassen hat. Ich verstehe 
auch nicht das Problem. Welchen Vorteil hat man denn, wenn alle 
blödsinnigen (wie du selbst schreibst) Konstrukte genau definiert sind?

A. K. schrieb:
> In diesem Fall bin ich mir in C99 nicht so sicher.

> `whose value depends upon the order in which side effects are
> evaluated´. Es ist also nicht entscheidend, wie oft geschrieben wird,
> sondern ob sich durch eine andere Reihenfolge etwas ändern kann. Was
> hier nicht der Fall ist.

Entscheiden dafür, ob es eine "ambiguous expression" ist. Die Rationale 
ist auch nicht normativ.
Normativ ist in C99 das hier (§6.5 "Expressions"):

"Between the previous and next sequence point an object shall have its 
stored value modified at most once by the evaluation of an expression. 
Furthermore, the prior value shall be read only to determine the value 
to be stored."

Und das ist genau das, was hier schon geschrieben wurde, und es gilt 
ohne Ausnahme. Dazu sind übrigens auch Beispiele angegeben:

"This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;"

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Rolf M. schrieb:
> Damit legst du an einigen Stellen eine bestimmte Reihenfolge fest, wo
> man in C bewusst dem Compiler die Freiheit gelassen hat. Ich verstehe
> auch nicht das Problem. Welchen Vorteil hat man denn, wenn alle
> blödsinnigen (wie du selbst schreibst) Konstrukte genau definiert sind?

 Gar keinen, natürlich.
 Aber das sind nicht die Begrenzungen der Sprache, es ist der
 Optimizer. Warum ein Ausdruck, der sich ohne Probleme parsen und
 ausführen lässt, undefiniertes Ergebnis liefern soll, ist für mich
 nur schwer oder überhaupt nicht zu verstehen.

 Hat natürlich nichts damit zu tun, ob ein Ausdruck Sinn ergibt
 oder nicht.

 Wie schon geshrieben:
A. K. schrieb:
> PS: Dass man so einen Stuss nicht schreiben sollte ist klar.

von Carl D. (jcw2)


Lesenswert?

Nur weil man sich ins Knie schießen könnte, muß man es doch nicht tun. 
Man darf alles auch so schreiben, daß man es morgen noc versteht.
Der Compiler hat gewarnt, er kann auch dazu gebracht werden dafür Fehler 
zu werfen, was braucht man mehr. Solange man noch Warnungen hat, hat man 
sich nicht klar genug ausgedrückt. Also nacharbeiten!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Marc V. schrieb:
>  Aber das sind nicht die Begrenzungen der Sprache, es ist der
>  Optimizer. Warum ein Ausdruck, der sich ohne Probleme parsen und
>  ausführen lässt, undefiniertes Ergebnis liefern soll, ist für mich
>  nur schwer oder überhaupt nicht zu verstehen.
>
>  Hat natürlich nichts damit zu tun, ob ein Ausdruck Sinn ergibt
>  oder nicht.

Es würde nicht bei so einfachen Dingen wie x = x++ bleiben, sondern es 
müssten alle Abartigkeiten spezifiziert werden.  Das würde werder ein 
Mehrgewinn für den Sprachstandard bedeuten, noch für in der Sprache 
geschriebene Programme, noch für Compiler welche die Sprache 
implementieren.

Der tiefere Grund ist aber folgender: C beschreibt das Verhalten einer 
abstrakten Maschine.  Wenn man sich nun z.B. auf den Wert einer 
Variablen X bezieht, dann beziehnt man sich also auf den Zustand der 
abstrakten Maschine.  Der Standard legt nun fest, zu welchen Zeitpunkten 
die reale Maschine, welche ein C-Programm ausführt, mit dem Zustand der 
abstrakten, durch den Standard beschriebenen Maschine übereinzustimmen 
hat.  Das sind die bekannten Sequence-Points, und die sind nun mal so 
festgelegt, dass x = x++ eben nicht definiert ist, weil 2x auf x 
geschrieben wird.

Falls das mit der abstrakten Maschine zu abstrakt ist, kannst du mal der 
konkreten Frage nachgehen, warum wohl

LD R26, X+

auf der konkrete AVR-Architektur nicht definiert ist :-)

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
>>  Hat natürlich nichts damit zu tun, ob ein Ausdruck Sinn ergibt
>>  oder nicht.
>
> Es würde nicht bei so einfachen Dingen wie x = x++ bleiben, sondern es
> müssten alle Abartigkeiten spezifiziert werden.

Ich denke auch, dass das ein wesentlicher Punkt ist. Man sagt einfach 
mit einer kurzen Regel, dass solche Sachen alle undefiniert sind, statt 
tausend Regeln bauen zu müssen, damit jeder einzelne Fall auch sauber 
abgedeckt ist. Das hält auch die Sprachdefinition einfach.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Johann L. schrieb:
> Falls das mit der abstrakten Maschine zu abstrakt ist, kannst du mal der

 Es ist mir nicht zu abstrakt, danke der Nachfrage.

> konkreten Frage nachgehen, warum wohl
> LD R26, X+
> auf der konkrete AVR-Architektur nicht definiert ist :-)

 Und
1
      ld   r26, X+
 ist definiert, nur das Resultat ist nicht definiert ;-)

 Was nicht weiter verwunderlich ist, denn wohin X auch zeigt und
 welches register zuerst geladen wird, ob xl oder xh ist egal - X
 zeigt nicht mehr dort, wo er vorhin gezeigt hat.
 Insofern ist das Resultat undefiniert - es wird nicht der Wert aus
 der ursprünglichen Adresse geladen und X wird zum Schluss auch
 nicht X+1 sein.

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

A. K. schrieb:
> Aus (1)
>
>> Sobald zwischen zwei sequence points mehr als
>> einmal schreibend auf eine Variable zugegriffen wird, wird undefiniertes
>> Verhalten erzeugt.
>
> wird diesem Text zufolge also (2)
>
>> Sobald zwischen zwei sequence points mehr als
>> einmal schreibend auf eine Variable zugegriffen wird, kann undefiniertes
>> Verhalten erzeugt werden.

Dieser Thread erklärt das ganz gut:
http://stackoverflow.com/questions/13714246/assignment-and-sequence-points-how-is-this-ambiguous


Marc V. schrieb:
> Warum ein Ausdruck, der sich ohne Probleme parsen und
>  ausführen lässt, undefiniertes Ergebnis liefern soll, ist für mich
>  nur schwer oder überhaupt nicht zu verstehen.

Weil der Compiler das nicht zu 100% prüfen kann (Zeiger, Casts, 
verschiedene Sourcen etc.). Also überlässt man diese Verantwortung dem 
Programmierer.

von Peter D. (peda)


Lesenswert?

Mark schrieb:
> wenn ich maincounter++ mit maincounter+1 ersetze, funktioniert es. Wieso
> wird ++ nicht erkannt?

Nimm einfach die Bedingung raus und dann steht da.
1
maincounter = maincounter++;
Das meckert der Compiler völlig zu recht an.
Es ist nicht definiert, welche der beiden Zuweisungen zuerst erfolgt.
Erfolgt die rechte zuerst, bleibt maincounter unverändert.
1
// erst rechts:
2
temp = maincounter;
3
maincounter = maincounter + 1; // post increment
4
// dann links:
5
maincounter = temp;

Erlaubt ist dagegen:
1
maincounter = (maincounter++ >= 250) ? 0 : maincounter;
Das ? ist nämlich ein sequence point und damit erfolgt die rechte 
Zuweisung immer zuerst.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter D. schrieb:
> Es ist nicht definiert, welche der beiden Zuweisungen zuerst erfolgt.
> Erfolgt die rechte zuerst, bleibt maincounter unverändert.// erst
> rechts:
> temp = maincounter;
> maincounter = maincounter + 1; // post increment
> // dann links:
> maincounter = temp;

 Mit optimieren ?
 Warum Zwischenregister Links ?
1
   lds  tmp, maincounter   ;* Rechte Seite
2
   sts  maincounter, tmp   ;* Linke Seite ( ergibt: maincounter = maincounter)
3
   inc  tmp                ;* postincrement
4
   sts  maincounter, tmp   ;* update maincounter

 y = x++;
1
   lds  tmp, x             ;* Rechte Seite
2
   sts  y, tmp             ;* Linke Seite ( ergibt: y = x)
3
   inc  tmp                ;* postincrement
4
   sts  x, tmp             ;* update x

von avr (Gast)


Lesenswert?

Wie wärs wenn du es wenigstens mal versuchst zu verstehen? Ich übersetze 
dir mal den C-Code von Peter nach Assembler falls das hilft.
1
   lds  tmp, maincounter   ;* Rechte Seite zwischenspeichern
2
   lds  tmp2, maincounter  ;* Rechte Seite
3
   inc  tmp2               ;* postincrement
4
   sts  maincounter, tmp2  ;* update maincounter
5
   sts  maincounter, tmp   ;* Linke Seite ( ergibt: maincounter = maincounter)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

avr schrieb:
> Wie wärs wenn du es wenigstens mal versuchst zu verstehen? Ich übersetze
> dir mal den C-Code von Peter nach Assembler falls das hilft.

 Wie wäre es wenn du dich mal ein bisschen über optimieren
 informierst ?
 Das, was du so unglücklich zu übersetzen versucht hast, braucht
 2 Bytes, 2 Takte und einen Register mehr als das, was ich gepostet
 habe.
 Was bringt dich zu der Annahme, dass der Compiler die längere und
 langsamere Variante wählen wird ?

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Marc V. schrieb:
> avr schrieb:
>> Wie wärs wenn du es wenigstens mal versuchst zu verstehen? Ich übersetze
>> dir mal den C-Code von Peter nach Assembler falls das hilft.
>
>  Wie wäre es wenn du dich mal ein bisschen über optimieren
>  informierst ?
>  Das, was du so unglücklich zu übersetzen versucht hast, braucht
>  2 Bytes, 2 Takte und einen Register mehr als das, was ich gepostet
>  habe.
>  Was bringt dich zu der Annahme, dass der Compiler die längere und
>  langsamere Variante wählen wird ?

Vielleicht die Tatsache, daß y und x nicht das Gleiche sind?

Wer das Problem nicht verstanden hat, tut sich auch mit dessen Lösung 
schwer.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Carl D. schrieb:
> Wer das Problem nicht verstanden hat, tut sich auch mit dessen Lösung
> schwer.

 Genau.
 Warum meldest du dich dann überhaupt zu Wort ?

 Nicht die Sprache ist das Problem, sondern der Optimizer.
 Damit der immer optimal arbeitet, werden solche Situationen und
 deren Ergebnisse immer als undefiniert bezeichnet, soll heissen:

 Es kann gut gehen, genauso aber kann es in die Hose gehen.

 Aber solche Experten wie du und dein Vorredner (avr-Gast) sind
 weit davon entfernt, dies auch nur ansatzweise zu verstehen.

von avr (Gast)


Lesenswert?

Marc V. schrieb:
> Wie wäre es wenn du dich mal ein bisschen über optimieren
>  informierst ?

Du bist genau so weit wie vorher: Bockig und nicht gewillt etwas zu 
verstehen.

-Der AVR-Core ist bei weitem nicht die einzige Zielplattform für 
C-Compiler. Ein C-Compiler muss die Plattform nicht einmal kennen.
-Optimizer können sich durchaus irren und das kommt auch immer wieder 
vor.
-Nur weil du beim AVR die kürzere Variante zufällig dein gewünschtes 
Ergebnis hevorbringt, ist das sicherlich nicht auf allen Architekturen 
so => undefined behaviour

Abgesehen davon: Wie kommt man eigentlich darauf aus kürzerem 
Assemblercode darauf zu schließen, wie der Compiler Code zu 
interpretieren hat? Der Assemblercode kommt erst am Ende, da hat der 
Compiler sich schon entschieden. Und wenn er sich für die andere 
Variante entschieden hat, dann wird die auch so umgesetzt. Und dann wird 
aus der "langen" Variante durch den Optimizer plötzlich was viel 
kürzeres. Nämlich gar nichts, weil dieser merkt, dass der Code nichts 
macht.

von Fritz G. (fritzg)


Lesenswert?

Be S. schrieb:
> Ich verstehe deine Einwände, dass man die Operation in solch simplen
> Fällen auch hätte definieren können. Macht aber keinen Sinn, denn dann
> hätte man konsequenterweise auchx = x++ + ++x;undy[x++] = ++x;definieren
> müssen.

Deswegen, und wegen dem Rest vom Thread, wurde in Swift 3 Pre- und 
Postincrement abgeschafft.
Verwirrt mehr als es nutzt, zumal es das bekannte for (int i=0;i<10;i++) 
auch nicht mehr gibt.

von avr (Gast)


Lesenswert?

Marc V. schrieb:
> Aber solche Experten wie du und dein Vorredner (avr-Gast) sind
>  weit davon entfernt, dies auch nur ansatzweise zu verstehen.

Ein Geisterfahrer? Tausende!

Fritz G. schrieb:
> Deswegen, und wegen dem Rest vom Thread, wurde in Swift 3 Pre- und
> Postincrement abgeschafft

Nur weil einer Beratungsresistent ist? Die Reihenfolge ist eben nicht 
definiert. So schwer kann das doch nicht sein. In Java wurde auch die 
Operatorüberladung abgeschafft. Einen sinvollen Grund dafür kenne ich 
bis heute nicht.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

avr schrieb:
> Nur weil einer Beratungsresistent ist?

 Du willst mich beraten ?
 LOL.

avr schrieb:
> In Java wurde auch die
> Operatorüberladung abgeschafft. Einen sinvollen Grund dafür kenne ich
> bis heute nicht.

 Eben.
 Du kennst den Grund nicht.

von Axel S. (a-za-z0-9)


Lesenswert?

Marc V. schrieb:
> Was bringt dich zu der Annahme, dass der Compiler die längere und
>  langsamere Variante wählen wird ?

Und was bringt dich zu der Annahme, die kürzere Variante wäre 
besser/korrekter/schöner [1] als die längere?

[1] nichtzutreffendes streichen

Das ist doch die Crux der ganzen Diskussion. Der C-Ausdruck x = x++ kann 
ganz legal auf zwei verschiedene Weisen interpretiert werden, die aber 
dummerweise verschiedene Resultate liefern. Und zwar deswegen, weil der 
Inkrement-Operator selber bereits eine Zuweisung an x vornimmt und es in 
C keine Regel gibt in welcher Reihenfolge die Zuweisungen ausgeführt 
werden wenn sich kein Sequenzpunkt dazwischen befindet.

Deswegen sagt der C-Standard "das Verhalten ist undefiniert" und jeder 
vernünftige Programmierer wird einen solchen Ausdruck nicht verwenden. 
Und zwar deswegen, weil "vernünftig" einschließt, daß man nur Programme 
mit wohldefiniertem Verhalten schreibt. Um so mehr als

1. der Ausdruck sowieso keinen Sinn ergibt [2] und
2. jeder aktuelle Compiler eine Warnung dafür ausspuckt

Mir ist vollkommen schleierhaft, welchen weiteren Diskussionsbedarf es 
an dieser Stelle geben könnte.

[2] nehmen wir mal für einen Augenblick an, der Compiler befolgt deine 
Interpretation "erst die rechte Seiten komplett auswerten, inklusive 
aller Nebeneffekte und dann erst die Zuweisung machen" - dann steht da 
am Ende das Äquivalent von

tmp <- x    (Postfix-Inkrement liefert den alten Wert, also merken)
x <- x + 1  (Inkrement-Operatur inkl. Nebeffekt)
x <- tmp    (Zuweisung)

also ein teures NOP. Soll das ernsthaft deine "Lösung" sein?

von Axel S. (a-za-z0-9)


Lesenswert?

Marc V. schrieb:
> avr schrieb:
>> In Java wurde auch die
>> Operatorüberladung abgeschafft. Einen sinvollen Grund dafür kenne ich
>> bis heute nicht.
>
>  Eben.
>  Du kennst den Grund nicht.

1. du hast das "sinnvoll" unterschlagen
2. der Grund ist IMHO daß die Zielgruppe von Java all jene 
"Programmierer" sind, die ihre Lobotomie schon bekommen haben. Über die 
Sinnhaftigkeit kann man natürlich immer noch streiten ...

Wie man beim Design einer von Grund auf neuen Programmiersprache, die im 
Gegensatz zu C++ [1] keinerlei Zwängen zur Rückwärtskompatibilität [2] 
unterlegen ist, derart verkacken kann, wird mir ewig ein Rätsel bleiben.


[1] dem mehr oder weniger offiziellen #1 Vorgänger/Konkurrenten, der 
durch Java ersetzt werden sollte

[2] 99% aller Stellen, wo C++ unlogisch ist, folgen aus der zwingend 
geforderten Rückwärtskompatibilität zu C

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Axel S. schrieb:
> [2] nehmen wir mal für einen Augenblick an, der Compiler befolgt deine
> Interpretation "erst die rechte Seiten komplett auswerten, inklusive
> aller Nebeneffekte und dann erst die Zuweisung machen" - dann steht da
> am Ende das Äquivalent von
>
> tmp <- x    (Postfix-Inkrement liefert den alten Wert, also merken)
> x <- x + 1  (Inkrement-Operatur inkl. Nebeffekt)
> x <- tmp    (Zuweisung)
>
> also ein teures NOP. Soll das ernsthaft deine "Lösung" sein?

 Hast du überhaupt gesehen, was da passiert ?

 Erstens passiert das bei meiner "Lösung" mit Sicherheit nicht, das
 ist bei Danneggers "Lösung" der Fall.

 Zweitens ist das nicht meine "Lösung", sondern nur der schnellste
 Weg.

 Drittens, wir sind so ziemlich alle einer Meinung was das Resultat
 betrifft - nur bei der Frage, ob und warum das gerade so sein muss,
 gingen die Meinungen auseinander.

 Auf alle Fälle gilt für mich immer noch das oben gesagte:
Marc V. schrieb:
> Wenn es um Standard geht, ist es eine ganz andere Sache - da kann
>  auch drin stehen, dass a + 3 immer 9 ergibt, unabhängig vom Wert der
>  Variable a.
>  Wenn ich diese Sprache benutzen will, muss ich damit leben.
>  Genauso ist es mit a = a++;
>
>  Ob das aber einen Sinn ergibt, ist wiederum eine ganz andere Sache.

 Ich habe keinen Problem damit, aber anscheinend die anderen - wie
 wagst du es überhaupt, an der Logik der C Sprache und dessen
 Optimizer zu zweifeln - und ähnliches.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc V. schrieb:
> Ich habe keinen Problem damit, aber anscheinend die anderen - wie
>  wagst du es überhaupt, an der Logik der C Sprache und dessen
>  Optimizer zu zweifeln - und ähnliches.

 Es gab mal eine Diskussion darüber, warum FIAT bei einigen seinen
 LKWs Lenkrad rechts eingebaut hat, obwohl die für italienischen bzw.
 kontinentalen und nicht für englischen Markt vorgesehen waren.
 Keiner wusste eine vernünftige Antwort darauf, aber die anfängliche
 Diskussion wurde immer mehr zur Streiterei, am Ende hiess es:
 - du kannst nicht fahren, du hast keine Ahnung, du hast ja nicht mal
 ein Führerschein, meine Oma fährt besser als du und ähnlich.
 Bis mir mal ein Nachbar, der sein Leben lang LKWs gefahren hat, die
 Antwort sagte:
 Weil es auf engen Gebirgsstrassen in Rechtskurven besser ist,
 rechts zu sitzen, anstatt links - man kann den Abstand viel besser
 einschätzen. Ob nun rechts ein Abgrund oder eine Felswand ist -
 rechtssitzend sieht man halt alles besser. In den Linkskurven
 dagegen ist es egal - da ist die andere Fahrbahnhälfte dazwischen.

 Und genauso scheint es hier zu sein:
 Keiner weiss genau warum das so ist, ob es so sein muss, ob es so
 besser oder schlechter ist, aber derjenige mit einer anderen
 Meinung muss ganz einfach keine Ahnung haben.
 Dass sie aber selber keine vernünftige Antwort auf die Frage wissen,
 tut ja nichts zur Sache - der andere ist halt dumm, stur, bockig und
 ungebildet...

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Marc V. schrieb:
> avr schrieb:
>> Wie wärs wenn du es wenigstens mal versuchst zu verstehen? Ich übersetze
>> dir mal den C-Code von Peter nach Assembler falls das hilft.
>
>  Wie wäre es wenn du dich mal ein bisschen über optimieren
>  informierst ?

Nirgends in C ist Optimierung gefordert. Es gibt keinen Zwang, den 
schnellstmöglichen Weg umzusetzen. Man kann den Optimizer auch 
ausgeschaltet lassen, und auch dann muss der Compiler korrekten Code 
erzeugen.

>  Das, was du so unglücklich zu übersetzen versucht hast, braucht
>  2 Bytes, 2 Takte und einen Register mehr als das, was ich gepostet
>  habe.

Wenn dein Beispiel mit einem Compiler auf einer Architektur in einer 
Situation schneller ist, läßt das nicht den Rückschluss zu, dass alle 
Compiler auf allen Plattformen in allen Fällen das auch genau so 
umsetzen.
Übrigens habe ich auch schon im echten Leben gesehen, das auf zwei 
Systemen unterschiedliche Ergebnisse rausgekommen sind. Das ist schon 
ein paar Jahre he, es waren soweit ich mich erinnern kann ein PC und 
eine Sun-Workstation mit irgendeinem SPARC-Prozessor. Da ich damals auch 
schon viel über das Thema undefiniertes Verhalten diskutiert habe, war 
das immer das erste, was ich auf jedem System mal ausprobiert habe, um 
zu sehen, ob's tatsächlich auch in der Praxis Unterschiede gibt - und es 
gibt sie!

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.