Ich habe diese Frage in einem Test gesehen, in dem wir die Ausgabe des folgenden Codes mitteilen müssen.
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
Die Ausgabe ist -1
. Ich bin mir jedoch nicht sicher, warum dies die Antwort ist.
Was bedeutet der Ausdruck +(+k--)
in C?
k=k++
ist undefiniert, aber nicht undefiniert, weil es aufgrund eines verschleierten Zustands nie ausgeführt wird - stimme ich dafür, als Duplikat dieser Frage zu schließen .Antworten:
[Für die Aufzeichnung habe ich diese Antwort ziemlich erheblich bearbeitet, da sie akzeptiert und abgestimmt wurde. Es sagt aber immer noch im Grunde die gleichen Dinge.]
Dieser Code ist zutiefst, vielleicht absichtlich, verwirrend. Es enthält eine eng abgewendete Instanz des undefinierten Dread- Verhaltens . Es ist grundsätzlich unmöglich festzustellen, ob die Person, die diese Frage konstruiert hat, sehr, sehr klug oder sehr, sehr dumm war. Und die "Lektion", über die dieser Code Sie unterrichten oder befragen könnte - nämlich, dass der unäre Plus-Operator nicht viel tut - ist sicherlich nicht wichtig genug, um diese Art von subversiver Fehlleitung zu verdienen.
Es gibt zwei verwirrende Aspekte des Codes, die seltsame Bedingung:
und die wahnsinnige Aussage, die es kontrolliert:
Ich werde zuerst den zweiten Teil behandeln.
Wenn Sie eine solche Variable haben
k
, die Sie um 1 erhöhen möchten, bietet C Ihnen nicht eine, nicht zwei, nicht drei, sondern vier verschiedene Möglichkeiten:k = k + 1
k += 1
++k
k++
Trotz dieser Prämie (oder vielleicht gerade deswegen) sind einige Programmierer verwirrt und husten Verrenkungen wie
Wenn Sie nicht herausfinden können, was dies tun soll, machen Sie sich keine Sorgen: Niemand kann. Dieser Ausdruck enthält zwei verschiedene Versuche,
k
den Wert zu ändern (dask =
Teil und dask++
Teil). Da es in C keine Regel gibt, die besagt, welche der versuchten Modifikationen "gewinnt", ist ein Ausdruck wie dieser formal undefiniert , was nicht nur das bedeutet es hat keine definierte Bedeutung, aber das gesamte Programm, das es enthält, ist verdächtig.Nun, wenn man sich sehr sorgfältig, werden Sie , dass in diesem speziellen Programm sehen, die Linie
k = k++
nicht tatsächlich ausgeführt werden, weil (wie wir über zu sehen sind) die Kontrolle Zustand anfänglich falsch ist, so dass die Schleife 0 mal läuft . Also dieses besondere Programm möglicherweise nicht tatsächlich undefiniert sein - aber es ist immer noch pathologisch verwirrend.Siehe auch diese kanonischen SO-Antworten auf alle Fragen zu undefiniertem Verhalten dieser Art.
Aber du hast nicht nach dem
k=k++
Teil gefragt . Sie haben nach dem ersten verwirrenden Teil gefragt, dem+(+k--)!=0
Zustand. Das sieht seltsam, denn es ist seltsam. Niemand würde jemals einen solchen Code in ein echtes Programm schreiben. Es gibt also keinen Grund zu lernen, wie man es versteht. (Ja, es ist wahr, das Erforschen der Grenzen eines Systems kann Ihnen helfen, seine Feinheiten kennenzulernen, aber in meinem Buch gibt es eine ziemlich klare Grenze zwischen einfallsreichen, zum Nachdenken anregenden Erkundungen und düsteren, missbräuchlichen Erkundungen, und dieser Ausdruck ist sehr deutlich die falsche Seite dieser Linie.)Wie auch immer, lassen Sie uns untersuchen
+(+k--)!=0
. (Und nachdem wir das getan haben, vergessen wir alles.) Jeder Ausdruck wie dieser muss von innen nach außen verstanden werden. Ich nehme an, du weißt wastut. Es nimmt
k
den aktuellen Wert und "gibt" ihn an den Rest des Ausdrucks zurück und dekrementiert mehr oder weniger gleichzeitig, dhk
es speichert die Mengek-1
zurück ink
.Aber was macht das
+
dann? Dies ist ein unäres Plus, kein binäres Plus. Es ist wie ein unäres Minus. Sie wissen, dass das binäre Minus subtrahiert: der Ausdrucksubtrahiert b von a. Und Sie wissen, dass unäres Minus die Dinge negiert: den Ausdruck
gibt Ihnen das Negativ von a. Was Unary
+
tut, ist ... im Grunde nichts.+a
gibt Ihnena
den Wert, nachdem Sie positive Werte in positive und negative Werte in negative geändert haben. Also der Ausdruckgibt dir, was
k--
dir gegeben hat, das istk
der alte Wert.Aber wir sind noch nicht fertig, weil wir haben
Dies nimmt nur das, was
+k--
Sie gegeben haben, und gilt wieder ungleichmäßig+
. Also gibt es dir, was+k--
dir gegeben hat, wask--
dir gegeben hat, wask
der alte Wert war.Also am Ende die Bedingung
macht genau das Gleiche wie der viel gewöhnlichere Zustand
hätte es getan. (Es macht auch das Gleiche wie die noch komplizierter aussehende Bedingung
while(+(+(+(+k--)))!=0)
. Und diese Klammern sind nicht wirklich notwendig; es macht auch das Gleiche wiewhile(+ + + +k--!=0)
es getan hätte.)Sogar herauszufinden, was der "normale" Zustand ist
tut ist irgendwie schwierig. In dieser Schleife gibt es zwei Dinge: Da die Schleife möglicherweise mehrmals ausgeführt wird, werden wir:
k--
, um immerk
kleiner zu machen , aber auchAber wir erledigen den
k--
Teil sofort, bevor wir (oder gerade) entscheiden, ob wir eine weitere Reise durch die Schleife unternehmen wollen. Und denken Sie daran, dassk--
der alte Wert von "zurückgegeben" wirdk
, bevor er dekrementiert wird. In diesem Programm ist der Anfangswert vonk
0.k--
Der alte Wert 0 wird also "zurückgegeben" und dannk
auf -1 aktualisiert . Aber dann ist der Rest der Bedingung!= 0
- aber wie wir gerade gesehen haben, haben wir beim ersten Testen der Bedingung eine 0 erhalten. Wir werden also keine Fahrten durch die Schleife machen, also werden wir nicht versuchen, die auszuführen überhaupt problematische Aussagek=k++
.Mit anderen Worten, in dieser speziellen Schleife stellt sich heraus, dass Sache 1 einmal passiert, Sache 2 jedoch null Mal, obwohl ich gesagt habe, dass "zwei Dinge vor sich gehen".
Auf jeden Fall hoffe ich, dass jetzt hinreichend klar ist, warum diese schlechte Entschuldigung für ein Programm am Ende -1 als Endwert von druckt
k
. Normalerweise beantworte ich Quizfragen wie diese nicht gerne - es fühlt sich an wie Betrug -, aber in diesem Fall macht es mir nichts aus, da ich mit dem ganzen Punkt der Übung so lautstark nicht einverstanden bin.quelle
Auf den ersten Blick sieht es so aus, als würde dieser Code undefiniertes Verhalten hervorrufen, was jedoch nicht der Fall ist.
Lassen Sie uns zuerst den Code richtig formatieren:
Jetzt können wir also sehen, dass sich die Anweisung
k=k++;
innerhalb der Schleife befindet.Verfolgen wir nun das Programm:
Wenn die Schleifenbedingung zum ersten Mal ausgewertet wird,
k
hat sie den Wert 0. Der Ausdruckk--
hat den aktuellen Wert vonk
0 undk
wird als Nebeneffekt dekrementiert. Nach dieser Anweisung ist der Wert vonk
-1.Der führende
+
Wert für diesen Ausdruck hat keine Auswirkung auf den Wert, wird also+k--
mit 0 und in ähnlicher Weise+(+k--)
mit 0 bewertet.Dann wird der
!=
Bediener ausgewertet. Da0!=0
false ist, wird der Hauptteil der Schleife nicht eingegeben . Wäre der Body eingegeben worden, würden Sie undefiniertes Verhalten aufrufen, dak=k++
sowohl gelesen als auch geschrieben wird,k
ohne einen Sequenzpunkt. Aber die Schleife ist nicht eingegeben, also keine UB.Schließlich wird der Wert von
k
-1 gedruckt.quelle
if (x != NULL) *x = 42;
Ist das undefiniert wannx == NULL
? Natürlich nicht. Undefiniertes Verhalten tritt nicht in Teilen des Codes auf, die nicht ausgeführt werden. Das Wort Verhalten ist ein Hinweis. Code, der nicht ausgeführt wird, hat kein undefiniertes oder sonstiges Verhalten.k=k++
qualitativ anders ist als*x=42
. Letzteres ist genau definiert, wennx
es sich um einen gültigen Zeiger handelt, Ersteres ist jedoch undefiniert, egal was passiert. (Ich gebe zu, dass Sie vielleicht Recht haben, aber ich werde nicht darüber streiten, und ich mache mir zunehmend Sorgen, dass wir meisterhaft getrollt wurden.)Hier ist eine Version davon, die die Priorität des Operators zeigt:
Die beiden unären
+
Operatoren tun nichts, daher entspricht dieser Ausdruck genauk--
. Die Person, die dies geschrieben hat, hat höchstwahrscheinlich versucht, sich mit Ihrem Verstand herumzuschlagen.quelle