Gast
#4712890
@mod bitte verschieben wenn unpassendes forum "code" viel spass beim freitagsabtausch
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
|
Anzeige
|
* C++ == C++ *
Gast
#4712890
@mod bitte verschieben wenn unpassendes forum "code" viel spass beim freitagsabtausch
A is not A Da meckert schon der Compiler bzw. Linker:
Ersetzt ma print durch printf und inkludiert stdio.h, bleibt immer noch eine Warnung
Selbst wenn man C intialisiert, meckert der Compiler:
Der Ausdruck C++ == C++ ist nämlich gar nicht erlaubt, da er undefiniertes Verhalten bewirkt. Diese Diskussion um undefiniertes Verhalten – insbesondere im Zusammenhang mit den Operatoren ++ und --, hatten wir hier aber schon oft. PS: Der Clang-Compiler erläutert das Problem noch etwas dataillierter:
Es sind also tatsächlich die beiden ++, die sich gegenseitig beißen. Dass der Compiler da meckert ist ja klar. Das sollte eher eine kleine Denkaufgabe sein , die sich als gar nicht mal so einfach herausstellt. Ich nehme mal an C wird einfach irgendwo im Speicher festgelegt und hat halt einen bestimmten wert. Man muss sich nun ziemlich gut mit C auskennen um genau sagen zu können wie und wann welche Befehle ausgeführt werden. Mein Output : A is not A
Gast
#4712941
Maximilian S. schrieb: > Man muss sich nun ziemlich gut mit C > auskennen um genau sagen zu können wie und wann welche Befehle > ausgeführt werden. das hat aber wenig mit C zu tun. Man muss maximal seinen Compiler kennen. Denn hier kann jeder Compiler etwas anderes liefern. (sogar jede Version vom Compiler)
Gast
#4712955
Weil man eine Variable nur einmal pro Sequencepoint zuweisen darf. Ein Sequencepoint ist der Punkt ab dem eine Zuweisung zu einer Variablen für den Rest des Programm sichtbar wird. Beispielsweise ist jedes ';' ein solcher. Peter II schrieb: > Denn hier kann jeder Compiler etwas anderes liefern. (sogar jede > Version vom Compiler) Und sogar ein und der selbe Compiler in unterschiedlichen Optimierungsstufen. Es ist nicht einmal garantiert, dass das Programm überhaupt etwas ausgibt. Es könnte (zumindest theoretisch) sogar passieren, dass bei der Ausführung des Programms die Festplatte komplett gelöscht wird :) Selbst in diesem Fall wäre der Compiler immer noch ISO-konform.
Gast
#4712967
na dann nächste runde Yalu und auf die festplatte aufpassen! ;-)
gcc t.c && ./a.outp ??
Gast
#4712968
alles ist möglich!
Gast
#4712983
sicher den rechtschreibpatzer bemerkt aber vorsichtshalber: das 'p' am ende war zuviel gcc t.c && ./a.out ??
Gast
#4712988
8589934591
100000000
100000001
1
;-)
freitagsposter schrieb: > gcc t.c && ./a.out
Außerdem hast Du ein #include <stdio.h> vergessen ;-)
Gast
#4713001
Frank M. schrieb: > freitagsposter schrieb: >> gcc t.c && ./a.out$ gcc t.c && ./a.out > t.c: In function 'main': > t.c:6:4: error: width of 'x' exceeds its type > t.c:15:3: warning: large integer implicitly truncated to unsigned type > [-Woverflow] > t.c:19:3: error: 'for' loop initial declarations are only allowed in C99 > mode > t.c:19:3: note: use option -std=c99 or -std=gnu99 to compile your code > $ gcc -std=c99 t.c && ./a.out > t.c: In function 'main': > t.c:6:4: error: width of 'x' exceeds its type > t.c:9:18: error: expected declaration specifiers or '...' before numeric > constant > t.c:11:3: error: unknown type name 'uint33' > t.c:15:3: error: unknown type name 'uint33' > t.c:15:3: warning: overflow in implicit constant conversion [-Woverflow] dann taugt dein compiler (einstellung) nicht für ein 33 bit integer type
Gast
#4713003
das wäre die richtige antwort ;-) freitagsposter schrieb: > dann taugt dein compiler (einstellung) nicht für ein 33 bit integer type Bewahrt mich aber auch vor Unsinn ;-)
Gast
#4713013
Frank M. schrieb: > freitagsposter schrieb: >> dann taugt dein compiler (einstellung) nicht für ein 33 bit integer type > > Bewahrt mich aber auch vor Unsinn ;-) nur der mut zählt ;-) Yalu X. schrieb: > Es könnte (zumindest theoretisch) sogar passieren, dass bei der > Ausführung des Programms die Festplatte komplett gelöscht wird :) Gibts soeinen Compiler schon? Wäre ne coole ergänzung zu Suicide Linux: https://qntm.org/suicide, perfekt für den real programmer ;)
Gast
#4713035
Frank M. schrieb: > t.c: In function 'main': > t.c:6:4: error: width of 'x' exceeds its type > ...
x86-64 gcc 6.1 -xc -O2
Gast
#4713051
und jetzt?
Gast
#4713163
VS2012 C# kompiliert das ohne Probleme bzw. Warnung. Natürlich "A is not A"
Gast
#4713168
Ist auch interessant ;-) Daniel A. schrieb: > Yalu X. schrieb: >> Es könnte (zumindest theoretisch) sogar passieren, dass bei der >> Ausführung des Programms die Festplatte komplett gelöscht wird :) > > Gibts soeinen Compiler schon? Zumindest hat GCC in frühen Versionen in solchen Fällen auch schon mal "nethack" gespielt. :-) http://feross.org/gcc-ownage/ freitagsposter schrieb: > na dann nächste runde Yalu > und auf die festplatte aufpassen! > ;-) Ja, das ist schon interessanter :) Dazu muss erst einmal gesagt werden, dass der typeof-Operator kein ISO-C, sondern eine GNU-Erweiterung ist. Auch unsigned-long-Bitfelder sind Erweiterungen, die allerdings in der ISO-Norm explizit erlaubt werden. Leider kann ich in der Norm auf die Schnelle keine Informationen darüber finden, welchen Typ einzelne Bitfelder haben, wenn sie bspw. in arithmetischen Ausdrücken verwendet werden. Bei Bitfeldern mit erweiterten Datentypen (im vorliegenden Fall unsigned long int) scheint der GCC mit Integer-Typen mit "krummen" Bitbreiten zu arbeiten (hier mit "unsigned long int:33"). Im Gegensatz dazu haben beim Clang diese Bitfelder den Typ unsigned long int, weswegen das Verhalten der beiden Compiler an dieser Stelle unterschiedlich ist. Folgender Code
liefert mit dem GCC:
Die Ergebnisse werden also auf 33 Bit gestutzt. Beim Clang ist das nicht der Fall, da hier für die Berechnungen offensichtlich die volle Breite von 64 Bit genutzt wird:
Welcher der beiden Compiler nun recht hat, kann ich nicht sagen. Möglicherweise beide, da es hier ja um eine C-Erweiterung geht, bei denen die Norm den Compilern üblicherweise viel Freiheit lässt. Vielleicht findet aber auch jemand die Stelle in der Norm, wo solche Dinge genauer geregelt sind. Was das typeof betrifft: Witzigerweise kann man – wie in deinem Beispiel gezeigt – über dem Umweg über ein Bitfeld in einer Struktur und typeof auch ganz gewöhnliche Variablen als Bitfeld deklarieren, so dass bei der Arthmetik mit solchen Variablen die Ergebnisse ebenfalls auf eine krumme Bitzahl beschnitten werden. Das Ganze betrifft aber wohlbemerkt nur Bitfelder, die größer als int und damit C-Erweiterungen sind. Ein int-Bitfeld wird – unabhängig von der tatsächlichen Bitzahl – in Ausdrücken immer auf ein int erweitert. Somit sollten sich die beiden Compiler in diesem Fall gleich verhalten. Es ist müßig, eine "Denksportaufabe" zu undefiniertem Verhalten zu machen, denn: Sobald das ins Spiel kommt, ist jedes beliebige Ergebnis richtig. Es wäre sogar korrekt, wenn das Programm bei dieser if-Abfrage beide Zweige (also sowohl if, als auch else) ausführt, oder wenn es abstürzt oder eine unfreundliche E-Mail an deinen Chef sendet. In comp.lang.c wurden als Beispiel immer Dämonen, die aus deiner Nase kommen, genannt. Auch die wären nach ISO-C ein korrektes Ergebnis. ;-) Joachim D. schrieb: > A is not A Öhm nöö. A is A Erst wird verglichen, dann wird erhöht, zweimal. Günter X. schrieb: > Erst wird verglichen, dann wird erhöht, zweimal. Nein. Genau das ist eben nirgends so festgelegt. Es ist nur festgelegt, dass nach dem Vergleich C um zwei erhöht worden sein muss (naja, mal von der fehlenden Initialisierung abgesehen, die natürlich auch zu undefiniertem Verhalten führt – insbesondere dann, wenn C beispielsweise vorher zufällig MAX_INT war). Jörg W. schrieb: > Es ist nur festgelegt, dass nach dem Vergleich C um zwei erhöht > worden sein muss Streng genommen nicht einmal das. Undefined ist undefined, da ist einfach jede Annahme, egal wie plausibel sie klingen mag, potentiell falsch. Yalu X. schrieb: > Streng genommen nicht einmal das. Undefined ist undefined Stimmt auch wieder.
Gast
#4719417
Jörg W. schrieb: > Günter X. schrieb: >> Erst wird verglichen, dann wird erhöht, zweimal. > > Nein. Genau das ist eben nirgends so festgelegt. > > Es ist nur festgelegt, dass nach dem Vergleich C um zwei erhöht > worden sein muss (naja, mal von der fehlenden Initialisierung > abgesehen, die natürlich auch zu undefiniertem Verhalten führt – > insbesondere dann, wenn C beispielsweise vorher zufällig MAX_INT > war). Was NACH dem Vergleich passiert ist sowieso uninteressant, weil der Zustand von C nirgendwo im Programmchen abgefragt wird. BEIM Vergleich, VOR den beiden post increments, ist C auf jedem Fall gleich C. Die Antwort lautet daher "A is A". dulnik schrieb: > Die Antwort lautet daher "A is A". Noch einer, der's nicht kapieren will … dulnik schrieb: > Die Antwort lautet daher "A is A". Dann musst du sofort einen Bug-Report an die GCC- und Clang-Entwickler schreiben. Mit diesen Compilern ist die Ausgabe nämlich "A is not A". Nein, besser nicht ... war nur ein Scherz :) Yalu X. schrieb: > PS: Der Clang-Compiler erläutert das Problem noch etwas dataillierter: > warning: multiple unsequenced modifications to 'C' [-Wunsequenced] > if ( C++ == C++ ) { > ^ ~~ Auch der gcc kann das (-Wall -Wextra) warning: operation on 'c' may be undefined [-Wsequence-point] if (c++ == c++) { ^ Egal was da ausgegeben wird bzw. ob überhaupt was ausgeben wird, solchen Code schreibt man nicht (in mehrere Hinsicht) und @freitagsposter sollte einen auf den Deckel bekommen... steinadler schrieb: > int c = 5; > int pascal = 5; > > if (c++ == pascal) > { > print ( "C++ is Pascal\n" ); > } > else > { > print ( "C++ is not Pascal\n" ); > } > > Ist auch interessant ;-) Was ist daran interessant, was will der Künstler damit zum Ausdruck bringen?
Gast
#4720494
Jörg W. schrieb: > dulnik schrieb: >> Die Antwort lautet daher "A is A". > > Noch einer, der's nicht kapieren will … OK, ich habe zu schnell aus der Hüfte geschossen :-) Aber woran liegt das genau? Ich dachte die post inkrement operatoren werden nach dem Vergleich ausgeführt? Ist der Vergleich keine Expression im Sinne der Increment Funktionalität? dulnik schrieb: > OK, ich habe zu schnell aus der Hüfte geschossen :-) Aber woran liegt > das genau? Daran, dass du eben innerhalb einer Anweisung nur maximal eine Veränderung an einem Objekt durchführen darfst, egal ob nun durch Zuweisung, pre- oder post-In- oder Dekrement-Operatoren. Alles andere bewirkt gemäß Standard undefiniertes Verhalten. Der Hintergrund ist einfach, dass der Standard die Compilerhersteller nicht zu stark in ihrem Optimierungspotenzial bremsen möchte und ihnen so genügend Freiraum gibt, die einzelnen Teiloperationen beliebig in der Reihenfolge anzordnen. > Ich dachte die post inkrement operatoren werden nach dem > Vergleich ausgeführt? Genau das ist eben nicht festgelegt. Es ist nur festgelegt, dass der Vergleich den Wert von C von vor der Inkrementierung benutzen muss, aber das sagt nichts darüber aus, ob C zu dem Zeitpunkt, da der Vergleich stattfindet, bereits inkrementiert worden ist oder nicht. Also ich hab's mit gnu getestet und "A is A" (was auch zu erwarten war) Allerdings habe ich den Fehler der fehlenden Initialisierung kompensiert, sowas macht kein ersthafter Programmiere. Zudem steht in allmöglichen C Büchern die Auswirkung der Schreibweise ++i oder i++ Wer das irgnoriert sollte sich nicht ärgern wenn er Stunden beim sinnlosen debuggen verplämpert oder Stress vom Chef bekommt. Günter X. schrieb: > Also ich hab's mit gnu getestet und "A is A" (was auch zu erwarten war) Wieder einer, der noch nichts von diesem Thread verstanden hat. :-( Günter X. schrieb: > Also ich hab's mit gnu getestet und "A is A" (was auch zu erwarten war) Ja und ich mit gcc (Gentoo 4.9.3 p1.4, pie-0.6.4) 4.9.3:
Undefined eben.
Gast
#4721654
freitagsposter schrieb: > viel spass beim freitagsabtausch Die erste Frage ist, welche Sprache das im Beispiel ist. C oder C++ ist es wegen "void main" nicht, C# und Java haben meines Wissens kein print, Assembler, Fortran, Pascal, Cobol und so weiter ist es offensichtlich nicht… Also vor der Diskussion über den Standard, erstmal die Diskussion über die Sprache. [Hier fehlt mir jetzt doch ein passendes Smiley.] Daniel A. schrieb: > Ja und ich mit gcc (Gentoo 4.9.3 p1.4, pie-0.6.4) 4.9.3: > [...] > A is not A gcc 4.6.1: A is A gcc 4.7.4: A is A gcc 4.9.2: A is not A Wir können ja eine Strichliste machen, wer rechter hat ;-) Jörg W. schrieb: > Es ist nur festgelegt, dass > der Vergleich den Wert von C von vor der Inkrementierung benutzen > muss, aber das sagt nichts darüber aus, ob C zu dem Zeitpunkt, da der > Vergleich stattfindet, bereits inkrementiert worden ist oder nicht. Der erste Teil beschreibt klar die Regel welche im zweiten Teil wieder in Frage gestellt wird. Der Satz als solches ist nicht logisch. Ist das eine persönliche Interpretation oder gibt es für den Satz belastbare Beweise? Frank M. schrieb: > gcc 4.6.1: A is A > gcc 4.7.4: A is A > gcc 4.9.2: A is not A und jetzt bitte noch jerweils mit unterschiedlichen optimierungs optionen. Und selbst wenn: Das Verhalten ist undefined! sprich, wenn du zwei mal an verschiednen Stellen diese operation durchführst, muss nicht beide male das gleiche Ergebnis rauskommen. Das kann völlig davon abhängen, wie der Compiler den Code drum herum aufbaut. Wäre es "Implementation Defined" müsste es sich immer gleich verhalten und dokumentiert sein, aber bei "undefined" ist es "Zufall" Günter X. schrieb: > Der Satz als solches ist nicht logisch. Für dich vielleicht nicht, für mich schon. Die ganze Thematik wurde doch nun ausreichend hier auf und nieder gebetet. Wenn du's immer noch nicht glaubst, die Drafts des ISO-C-Standards kursieren frei im Internet. Lies sie einfach. Vlad T. schrieb: > und jetzt bitte noch jerweils mit unterschiedlichen optimierungs > optionen. Bringt nix. > Und selbst wenn: > Das Verhalten ist undefined! sprich, wenn du zwei mal an verschiednen > Stellen diese operation durchführst, muss nicht beide male das gleiche > Ergebnis rauskommen. Das kann völlig davon abhängen, wie der Compiler > den Code drum herum aufbaut. Vlad, ich weiß das. Ich wollte eigentlich nur darstellen, wie unsinnig eine Deutung des Ergebnisses ist. Deshalb schrieb ich "wer rechter hat". Ich kann damit leben das C vor der Abfrage = 0 ist, "A is A" raus kommt und am Ende in C 2 zu finden ist, das ergibt Sinn. Wer meint das anders sehen zu wollen kann das gerne machen. Das ein solcher Konstrukt in der Praxis nicht wirklich vorkommt entschärft die Sache dann komplett :) Günter X. schrieb: > Ist das eine persönliche Interpretation oder gibt es für den Satz > belastbare Beweise? Da das in den Standard selbst recht verschlüsselt ausgedrückt ist, hilft das C99 Rationale vom Standardisierungsgremium: "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. [...]. 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." Der Fall ist hier gegeben. *: Gibts innerhalb von "C++ == C++" nicht. Appendix C in C99/C11. PS: Es ist nicht nur offen, welcher Zweig ausgeführt wird. Es ist auch offen, ob C hinterher um 2 oder um 1 grösser ist. Man erhält bei "C++ == C++" beispielhaft drei Abläufe: (1) load T1, copy, increment, store - vom linken C++ (2) load T2, copy, increment, store - vom rechten C++ (3) compare T1 and T2 (nochmal: das ist nur ein Beispiel für mögliche Abläufe). Festgelegt ist hier nur, dass (3) nach dem Load in (1) und (2) stattfindet. Ansonsten darf der Compiler die Teiloperationen der 3 Abläufe beliebig ineinander verzahnen.
Gast
#4724432
Gast
#4724438
void main (void) {
int C;
if ( C++ == --C ) {
print ( "A is A\n" );
} else {
print ( "A is not A\n" );
}
}
Egal, wie viele Varianten du dir davon ausdenkst: sie erzeugen alle undefiniertes Verhalten. Noch was: keiner zwingt dich, beim Absenden deiner Postings eine Mailadresse einzutragen. Wenn du dich aber schon entscheidest, eine einzutragen, dann bitte eine, unter der dich die Forensoftware auch erreichen kann. Durch Angabe einer nicht existierenden Adresse outest du dich einfach nur als Troll.
Gast
#4724495
bei meinen Compiler kommt: Error, integer not initialized! 12: int C; heraus? Um das ein wenig auf die Spitze zu treiben - Du kannst mir doch sicher sagen, was hier rauskommen sollte:
Gast
#4724532
Jörg W. schrieb: > Egal, wie viele Varianten du dir davon ausdenkst: sie erzeugen > alle > undefiniertes Verhalten. dann definier sie dir doch, es kommt das "selbe" ergebnis hervor. > > Noch was: keiner zwingt dich, beim Absenden deiner Postings eine > Mailadresse einzutragen. Wenn du dich aber schon entscheidest, eine > einzutragen, dann bitte eine, unter der dich die Forensoftware auch > erreichen kann. Durch Angabe einer nicht existierenden Adresse > outest du dich einfach nur als Troll. du kennst doch meine email addresse ;-)
Gast
#4724536
A. K. schrieb: > Um das ein wenig auf die Spitze zu treiben - Du kannst mir doch > sicher > sagen, was hier rauskommen sollte: sollte 3 tun 4 Und was sagt dir das?
Gast
#4724542
Jörg W. schrieb: > Günter X. schrieb: >> Der Satz als solches ist nicht logisch. > > Für dich vielleicht nicht, für mich schon. für mich auch aber ich verstehe dein "aufkochen" an dem thread nicht jörg. es sollte eine "denksportaufgabe" sein, nichts weiter. dass jemand hier tatsächlich ein undefiniertes verhalten nachrechnet, wäre mir nie in den sinn. es geht um die feststellung, dass dies nicht im standard definiert ist. undefiniertes "verhalten" ;-) Sobald undefiniertes Verhalten ins Spiel kommt gibt es keine falschen Antworten mehr. Als "Denksport" ist das nicht sehr herausfordernd. freitagsposter schrieb: > dass jemand hier tatsächlich ein undefiniertes verhalten nachrechnet, > wäre mir nie in den sinn. es geht um die feststellung, dass dies nicht > im standard definiert ist. Du wolltest also nur feststellen, dass undefiniertes Verhalten nicht definiert ist? Andreas B. schrieb: > Sobald undefiniertes Verhalten ins Spiel kommt gibt es keine falschen > Antworten mehr. Als "Denksport" ist das nicht sehr herausfordernd. Wie ich ja schon vor über einer Woche in Beitrag "Re: * C++ == C++ *" geschrieben habe. Interessant, dass hier immer noch darüber diskutiert wird. Aber scheinbar ist es für manche doch mit einer größeren gedanklichen Anstrengung verbunden, zu erkennen, was undefiniert bedeutet.
Gast
#4724619
Rolf M. schrieb: > Aber scheinbar ist es für manche doch mit einer größeren gedanklichen > Anstrengung verbunden, zu erkennen, was undefiniert bedeutet. Ach für mich ist "undefiniertes Verhalten" ganz einfach, ich sehe das jeden Morgen: ab dem Zeitpunkt wenn meine Frau aufsteht bis zu ihrem ersten Kaffee ist das alles "undefiniertes Verhalten". Da lass ich auch lieber meine Finger davon. ;-) Es ist doch alles ganz einfach: Wird ein Ausdruck auf der linken Seite modifiziert, darf vor einem sequence point nicht ein weiteres mal davon gelesen werden. Der Compiler warnt einen dann:
test.c:6: warning: operation on 'i' may be undefined Erlaubt ist z.B.:
Peter D. schrieb: > Erlaubt ist z.B.: >
Ist aber schon fast IOCCC-verdächtig. ;-) Für die Strichliste: A is not A Apple LLVM version 8.0.0 (clang-800.0.38)
Gast
#4736762
Fritz G. schrieb: > Für die Strichliste: > > A is not A Interessant wäre, wo was ganz anderes rauskommt. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|