Auswertungsreihenfolge von Ausdrücken
-
kingruedi schrieb:
das ist sogar undefined behaviour
Das denke ich nicht. str wird hier nur genau einmal verändert. Außerdem wird der str-Wert einmal gelesen, aber nur um den neuen zu speichernden Wert zu bestimmen. Ansonsten wird hier nur dereferenziert. Also der Wert auf den str zeigt wird gelesen.
Sprich: ich sehe hier kein undefiniertes Verhalten. Lasse mich aber gerne eines Besseren belehren.
-
Also ich habe den Code getestet und es passiert absolut nichts. Keine Spur von undefiniertem Verhalten, macht immer das was es machen soll. Zudem habe ich sowas auch schonmal gemacht um für alle Zeichen den ASCII-Code zu ermitteln.
Code-Hacker
-
Code-Hacker schrieb:
Also ich habe den Code getestet und es passiert absolut nichts. Keine Spur von undefiniertem Verhalten, macht immer das was es machen soll.
Hm, "undefiniertes Verhalten" ist eine Quelltexteigenschaft. Solltest Du eine einigermaßen zurechnungsfähige Implementierung besitzen, so wird sie ein Programm erzeugen, das sehr wohl (durch die Umgebung) definiert ist. - Wie stellst Du Dir denn UB so vor?
Zudem habe ich sowas auch schonmal gemacht um für alle Zeichen den ASCII-Code zu ermitteln.
Eine gute Idee ist es trotzdem nicht, weil nicht klar ist, was miteinander verglichen wird.
-
oh, war etwas zu voreilig mit meiner Antwort
-
HumeSikkins schrieb:
Außerdem wird der str-Wert einmal gelesen, aber nur um den neuen zu speichernden Wert zu bestimmen. Ansonsten wird hier nur dereferenziert. Also der Wert auf den str zeigt wird gelesen.
IMHO muss der Zeigerwert gelesen werden, um dereferenziert werden zu können. Also doch UB.
-
Bashar schrieb:
HumeSikkins schrieb:
Außerdem wird der str-Wert einmal gelesen, aber nur um den neuen zu speichernden Wert zu bestimmen. Ansonsten wird hier nur dereferenziert. Also der Wert auf den str zeigt wird gelesen.
IMHO muss der Zeigerwert gelesen werden, um dereferenziert werden zu können. Also doch UB.
Hm, ich bin nicht überzeugt. Zweifle viel eher an der Richtigkeit der Aussage. In diesem Fall wäre nämlich auch
while (*(str++))
undefiniert. Und davon habe ich noch *nie* gehört. Könntest du deine Aussage noch etwas ausführen? Am Besten mit Referenzen auf den Standard?
-
HumeSikkins schrieb:
Könntest du deine Aussage noch etwas ausführen? Am Besten mit Referenzen auf den Standard?
Nein, leider nicht. Da muss ich selbst erstmal forschen. Fest steht aber, dass man nicht auf *p zugreifen kann ohne den Wert von p zu kennen
-
evtl Schnellschuss: bei *str++ wende ich * auf das Ergebnis von (str++) an, nicht auf str selbst. Es wird also nicht str nochmal gelesen. Das gilt selbst bei Präfix-++
-
also mal eine Erklärung, warum ich dachte, dass das UB sei:
bool b= *str==*++str;
zuerst kommt der == Operator dran
*str==*++str;
nun dachte ich, sei nicht definiert ob erst *++str; ausgewertet wird und dann *str oder andersrum. Also könnte es einmal äquivalent zu folgendem Code sein
char *ptr=str; *ptr==*++str;
und einmal zu
++str; *str==*str
wobei letzteres ja sicher nicht das ist, was Hoopi sucht
-
@kingruedi
Das Verhalten ist aus den von dir genannten Gründen auf jeden Fall unspecified. Die Frage ist halt, ob es auch UB ist.evtl Schnellschuss: bei *str++ wende ich * auf das Ergebnis von (str++) an, nicht auf str selbst. Es wird also nicht str nochmal gelesen. Das gilt selbst bei Präfix-++
Ok. Klar für *str++ bzw *str++ trifft der Schnellschuss. Das ist also auf jeden Fall legal.
Er klärt aber noch nicht das Verhalten von *str = *str++ oder *str = *++str.
str = str++ und str = ++str ist auf jeden Fall undefiniert soviel ist mir klar (genau wie f(str,++str))An die undefiniertheit von *str = *str++ oder *str = *++str bzw. f(*str, *++str) kann ich aber noch nicht recht glauben.
-
«the prior value shall be accessed only to determine the value to be stored» steht im Standard. Der Zugriff auf str in *str hat nicht diesen Zweck, der auf der rechten Seite schon. <imho> Ein Compiler müsste also erkennen, dass die beiden Zugriffe sich zu einem zusammenfassen lassen -- und genau das fordert das Standard mit diesem Satz explizit nicht. </imho>
-
@Bashar
Ok. Ich habe in comp.lang.c++ gefunden, dasscout << *p << *p++;
undefiniert ist. Also ist auch *str = *str++ und *str == *++str undefiniert.
-
Daniel E. schrieb:
Code-Hacker schrieb:
Also ich habe den Code getestet und es passiert absolut nichts. Keine Spur von undefiniertem Verhalten, macht immer das was es machen soll.
Hm, "undefiniertes Verhalten" ist eine Quelltexteigenschaft. Solltest Du eine einigermaßen zurechnungsfähige Implementierung besitzen, so wird sie ein Programm erzeugen, das sehr wohl (durch die Umgebung) definiert ist. - Wie stellst Du Dir denn UB so vor?
Zudem habe ich sowas auch schonmal gemacht um für alle Zeichen den ASCII-Code zu ermitteln.
Eine gute Idee ist es trotzdem nicht, weil nicht klar ist, was miteinander verglichen wird.
1. Kannst du das noch etwas genauer erläutern? Ich glaube ich habe eine ganz falsche Vorstellung von undefiniertem Verhalten....
2. Naja, das war ne schleife, die hat geguckt ob noch ein gültiges zeichen vorhanden ist, dann wurde der code ausgegeben und der zeiger erhöht, also nicht ganz das selbe.Code-Hacker
-
Code-Hacker schrieb:
1. Kannst du das noch etwas genauer erläutern? Ich glaube ich habe eine ganz falsche Vorstellung von undefiniertem Verhalten....
Es gibt 4 Abstufungen der Strenge, mit denen der Standard den Effekt einer bestimmten Konstruktion vorschreibt. Erstens ist das natürlich, dass das exakte Verhalten vorgeschrieben ist. Als nächstes haben wir "implementation defined". Der Effekt eines solchen Konstruktes steht nicht im Standard, sondern wird von jedem Implementor festgelegt und dokumentiert. Dazu gehören z.B. die Wertebereiche der einzelnen Typen. Das nächste ist "unspecified". Für ein solches Konstrukt existieren mehrere verschiedene sinnvolle Auslegungsweisen, die der Implementor nach Gutdünken auswählen kann und nicht dokumentieren muss. Dazu gehört z.B. die Reihenfolge, in der Funktionsargumente ausgewertet werden. Das letzt ist "undefiniert". Der Standard erlegt dem Implementor hier keinerlei Beschränkungen auf. Das hast du z.b., wenn du einen Nullpointer dereferenzierst: Unter MS-DOS wirst du schlicht und einfach den Inhalt der Speicherstelle 0 bekommen, Unix schickt dir ein SIGSEGV, Windows einen Bluescreen, der Z8 Microcontroller liest ein Zeichen vom seriellen Port oder so ... vom bösesten Absturz bis hin zu zufällig richtigen Ergebnissen ist alles möglich, aber theoretisch genauso gut, dass spontan Dämonen aus deiner Nase fliegen.