2013-08-22 17 views
7

Eine Frage wurde in einem Multiple-Choice-Test gefragt: Was ist die Ausgabe des folgenden Programms sein wird:Turbo C++: Warum druckt printf erwartete Werte, wenn keine Variablen an ihn übergeben werden?

#include <stdio.h> 

int main(void) 
{ 
    int a = 10, b = 5, c = 2; 

    printf("%d %d %d\n"); 

    return 0; 
} 

und die Entscheidungen waren verschiedene Permutationen von 10, 5 und 2. Aus irgendeinem Grund funktioniert es in Turbo C++, die wir in der Schule verwenden. Es ist jedoch nicht kompiliert mit gcc (die eine Warnung gibt, wenn -Wall aktiviert ist) oder Clam (die Wformat aktiviert hat und standardmäßig eine Warnung gibt) oder in Visual C++. Die Ausgabe ist wie erwartet Garbage-Werte. Meine Vermutung ist, dass es etwas mit der Tatsache zu tun hat, dass entweder Turbo C++ 16-Bit ist und auf 32-Bit Windows XP läuft, oder dass TCC schrecklich ist, wenn es um Standards geht.

+9

Ausgabe kann buchstäblich alles sein, da dieser Code in Undefined Behavior resultiert. –

+1

Ja, die ganze Compiler-Sache ist ein Ablenkungsmanöver. –

+0

Im gcc-Format muss der Spezifizierer einen Variablennamen benötigen, Beispiel printf ("% d", x); wenn nicht, druckt printf einen Wert – sujin

Antwort

20

Der Code lautet undefined behaviour.

In Turbo C++ passiert es einfach, dass die drei Variablen genau an den Positionen auf dem Stack liegen, an denen das fehlende printf() Argument stehen würde. Dies führt dazu, dass sich das undefinierte Verhalten manifestiert, indem die "korrekten" Werte gedruckt werden.

Sie können jedoch nicht vernünftigerweise darauf vertrauen, dass dies der Fall ist. Selbst die geringste Änderung an Ihrer Build-Umgebung (z. B. verschiedene Compiler-Optionen) könnte die Dinge auf eine unangenehme Art und Weise zerstören.

+0

Danke, das macht Sinn. Ich habe das gleiche Programm (kompiliert mit gcc) mehrmals unter Linux ausprobiert, und anscheinend ist dieser Zufall eher selten. Ist der Zufall, dass sie sich in den exakten Stapelpositionen befinden, die printf benötigt, etwas mit der Art und Weise zu tun, wie 16-Bit-Programme unter Windows XP ausgeführt werden? Etwas wie etwas Speicher ist wahrscheinlich reserviert, um genau dieses eine Programm auszuführen? – SgrA

+0

@SgrA: Ein paar Sterne müssen sich ausrichten, damit sich dieses Programm so verhält, wie Sie es beschreiben. Es wäre zu einfach zu sagen, dass es wegen XP oder weil das Programm 16-Bit ist. – NPE

+0

Das Interessante daran ist, dass es in Turbo C++ jedes Mal wie oben beschrieben funktioniert hat, aber nie außerhalb, was mich neugierig macht. – SgrA

4

Es ist ein undefined behaviour. Es könnte also alles sein.

Versuchen

printf("%d %d%d", a,b,c) 

Grund zu verwenden: - Lokale Variablen werden genannt auf dem Stapel und printf in Turbo C++ sieht sie in der gleichen Reihenfolge, in der sie in dem Stapel zugewiesen wurden.

SUGGESTION (Von Kommentare): -

zu verstehen, warum es mit einem bestimmten Compiler in einer bestimmten Art und Weise verhält, kann bei der Diagnose von Problemen nützlich sein, aber machen keine andere Verwendung der Informationen.

+0

Ja, ich bin überzeugt, dass die Ausgabe alles sein kann. Ich würde gerne wissen, warum es genau in Turbo C++ funktioniert. – SgrA

+0

NPE hat den Grund gegeben, der wahrscheinlich der beste ist !!! :) –

+0

@SgrA: - Meine Antwort mit dem Grund aktualisiert, obwohl NPE es besser erklärt hat !!! :) –

4

Die Antwort hier ist, dass das Programm alles tun konnte - das ist undefiniertes Verhalten. Nach printf() Dokumentation (Hervorhebung von mir):

Standardmäßig werden die Argumente in der angegebenen Reihenfolge verwendet, wobei jede ‚*‘ und jeder Konvertierungsspezifizierer für das nächste Argument fragt (und es ist ein Fehler, wenn unzureichend viele Argumente angegeben).

Wenn Ihr Multiple-Choice-Test keine Wahl für "undefiniertes Verhalten" hat, ist dies ein fehlerhafter Test. Unter dem Einfluss von undefiniertem Verhalten ist die beliebige Antwort auf eine solche Multiple-Choice-Testfrage technisch korrekt.

3

Was tatsächlich passiert, ist, dass Argumente normalerweise auf dem Aufruf-Stapel übergeben werden. Lokale Variablen sind auch auf dem Call-Stack übergeben, und so printf() sieht diese Werte, in welcher Reihenfolge der Compiler beschlossen, sie dort zu speichern.

Dieses Verhalten, sowie viele andere, sind unter dem Dach der undefined behavoir

+0

Sie meinen "lokale Variablen werden auch auf dem Stack platziert" statt "lokale Variablen werden auch auf dem Aufruf-Stack übergeben" ... – Floris

2

Nein, es ist nicht im Zusammenhang mit Architektur erlaubt. Es hängt damit zusammen, wie TurboC++ den Stack handhabt. Die Variablen a, b und c sind Einheimische und als solche im Stapel zugeordnet. printf erwartet auch die Werte im Stack. Anscheinend fügt TurboC++ dem Stack nach den Locals nichts anderes hinzu und printf kann sie als Parameter übernehmen. Nur Zufall.