2015-09-30 12 views
5

Was ist der Rückgabewert von f (p, p), wenn der Wert von p vor dem Aufruf auf 5 initialisiert wird? Beachten Sie, dass der erste Parameter als Referenz übergeben wird, während der zweite Parameter als Wert übergeben wird.ist undefiniertes Verhalten in gegebenem Code?

int f (int &x, int c) { 
     c = c - 1; 
     if (c==0) return 1; 
     x = x + 1; 
     return f(x,c) * x; 
} 

Optionen sind:


Ich versuche zu erklären:


In diesem Code wird es vier rekursive Aufrufe mit Parametern sein (6,4), (7,3), (8,2) und (9,1). Der letzte Aufruf gibt 1 zurück. Aber aufgrund des Verweises ist x in allen vorherigen Funktionen jetzt 9. Daher wird der von f (p, p) zurückgegebene Wert 9 * 9 * 9 * 9 * 1 = 6561.


Diese Frage ist von der Wettbewerbsprüfung GATE (see Q.no.-42). Der Antwortschlüssel wird durch GATE "Markiert für alle" angegeben (bedeutet, dass keine Option korrekt ist). key set-C, Q.no.-42. Irgendwo erklärt als:

In GATE 2013 wurden Marken für alle gegeben, da der gleiche Code in C/C++ undefiniertes Verhalten erzeugt. Dies liegt daran, dass * kein Sequenzpunkt in C/C++ ist. Der richtige Code muss

ersetzen
return f(x,c) * x; 

mit

res = f(x,c); 
return res * x; 

Aber der gegebenen Code funktioniert gut. Ist Gates Schlüssel falsch? Oder ist wirklich der Fehler bei der Frage?

+2

Eines der Dinge, die passieren können, wenn Sie die Straße überqueren, ohne in beide Richtungen zu schauen, ist, dass Sie es sicher auf die andere Seite schaffen. Aber es ist ein Fehler, * vorherzusagen *, dass eine Person, die die Straße überquert, ohne in beide Richtungen zu sehen, sicher zur anderen Seite gelangt. –

+0

Ähnlich wie [Sequenzpunkt Ambiguität, undefined Verhalten?] (Http://StackOverflow.com/Q/29513572/1708801) –

Antwort

14
return f(x,c) * x; 

Das Ergebnis dieser Operation hängt von der Reihenfolge ab, in der die beiden Dinge ausgewertet werden. Da Sie die Reihenfolge, in der sie ausgewertet werden, nicht vorhersagen können, können Sie das Ergebnis dieser Operation nicht vorhersagen.

+0

Sir, warum funktioniert hier [this-code] (http://cpp.sh/8m6y) –

+5

@ user4791206 Was meinst du mit "funktioniert gut"? Da Sie nicht vorhersagen können, was es tun wird, warum würden Sie sagen, was es passiert ist, funktioniert es gut? Jemand, der voraussagte, dass es in der anderen Reihenfolge bewertet würde, würde nicht sagen, dass es gut funktionierte, oder? –

+0

Bedeutet, Problem der Bewertungsreihenfolge ist undefiniertes Verhalten [I-lesen] (http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points)? –

9

C++ 03 Kapitel 5:

Soweit nicht anders angegeben, die Reihenfolge der Auswertung von Operanden von einzelnen Betreibern und Unterausdrücken einzelner Ausdrücke, und die Reihenfolge, in der Nebenwirkungen stattfinden, ist nicht spezifiziert.

So im Fall von f(x,c) * x, die Reihenfolge der Auswertung der Operanden ist nicht spezifiziert, was bedeutet, dass Sie nicht wissen, ob die linke oder rechte Operand zuerst ausgewertet erhalten wird.

Ihr Code hat nicht spezifiziertes Verhalten, was bedeutet, dass es sich in einer bestimmten definierten Weise verhalten wird, die nur dem Compiler bekannt ist.Der Programmierer kann nicht wissen, was der Code tun wird, nur dass er entweder zuerst den linken Operanden oder zuerst den rechten Operanden auswertet. Dem Compiler ist es sogar erlaubt, die Reihenfolge der Auswertung von Fall zu Fall zu Optimierungszwecken zu ändern.

Wenn die Reihenfolge der Auswertung wichtig ist, müssen Sie den Code neu schreiben. Code, der sich auf nicht spezifiziertes Verhalten stützt, ist immer ein Fehler, möglicherweise ein ganz subtiler, der nicht sofort auftaucht.

Nicht spezifiziertes Verhalten unterscheidet sich von undefiniertem Verhalten, was bedeuten würde, dass alles passieren könnte, einschließlich des Programms, das verrückt spielt oder abstürzt.

+2

Als eine Randnotiz unterscheidet sich der gleiche Text in C++ 11, hat aber die gleiche Bedeutung. Ich denke, C++ 11 (und C11) hat den Text nur viel schwerer verständlich gemacht, weshalb ich eine ältere Version des Standards zitiere. – Lundin

+0

Danke, mein Herr, ich habe es verstanden. –

+0

Im Allgemeinen bedeutet "nicht spezifiziertes Verhalten" nicht, dass ein Programmierer nicht wissen kann, was der Code tun wird - lediglich dass der Programmierer in keinem gegebenen Fall wissen kann, welches der möglichen Verhaltensweisen ein Compiler auswählt. Wenn alle möglichen Kombinationen des Compilerverhaltens die Anforderungen des Programmierers erfüllen würden, hätte ein Programmierer das Recht zu erwarten, dass das Programm korrekt funktioniert. Es ist nichts Falsches daran, dass sich der Code darauf verlässt, dass ein Compiler auf unbestimmte Weise aus definierten Aktionen auswählt, solange er mit einer solchen Auswahl arbeitet, die der Compiler gerade ausführt. – supercat