2016-10-03 2 views
0

In C ist es zulässig, eine Variable in derselben Anweisung zu verwenden, in der es deklariert ist?Deklarieren und verwenden Sie Variable in derselben Anweisung

Sowohl gcc 4.9 und 3.5 clang das folgende Programm kompiliert und läuft ohne Fehler:

#include "stdio.h" 

int main() { 
    int x = x; 
    printf("%d\n", x); 
} 

In gcc gibt sie 0 und in Klirren 32767 (die größte positive Zahl 2-Byte ist).

Warum verursacht dies keinen Kompilierungsfehler? Gilt dies in einer bestimmten C-Spezifikation? Ist das Verhalten explizit undefiniert?

+2

In MSVC gibt es "Warnung C4700: nicht initialisierte lokale Variable 'x' used" aus. Bitte aktivieren Sie die Compilerwarnungen, bevor Sie dumme Fragen stellen. –

+1

@WeatherVane: Die Tatsache, dass ein Compiler eine Warnung ausgibt, sagt Ihnen nicht, ob sie gültig ist. –

+0

MSVC Ausgänge zur Laufzeit '-1373317485' Nun, einmal, verschiedene Werte. –

Antwort

4
int x = x; 

Dies ist „gültig“ in dem Sinne, dass es nicht eine Einschränkung oder Syntaxregel verletzt, so dass keine Kompilierung-Diagnose erforderlich ist. Der Name x ist innerhalb des Initialisierers sichtbar und bezieht sich auf das deklarierte Objekt. Der Anwendungsbereich ist in N1570 6.2.1 Absatz 7 definiert:

Any other identifier [other than a struct, union, or enum tag, or an enum constant] has scope that begins just after the completion of its declarator.

Die declarator in diesem Fall ist int x.

Dies ermöglicht Dinge wie:

int x = 10, y = x + 1; 

Aber die Erklärung ist das Verhalten nicht definiert, weil der Initialisierer auf ein Objekt verweist, die nicht initialisiert wurde.

Die explizite Anweisung, dass das Verhalten nicht definiert ist, ist in N1570 6.3.2.1 Absatz 2, der die "Umwandlung" eines lvalue (ein Ausdruck, der ein Objekt bezeichnet) mit dem in diesem Objekt gespeicherten Wert beschreibt.

Except when [list of cases that don't apply here], an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.
[...]
If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

Das betreffende Objekt ist x, in der Initialisierungsliste verwiesen. Zu diesem Zeitpunkt wurde x kein Wert zugewiesen, daher hat der Ausdruck ein undefiniertes Verhalten.

In der Praxis erhalten Sie wahrscheinlich eine Kompilierungswarnung, wenn Sie eine ausreichend hohe Warnstufe aktivieren. Die tatsächliche Verhalten Macht das gleiche sein, wie wenn Sie die initializer ausgelassen hatten:

int x; 

aber zählen nicht darauf.

+0

Würde es einen Unterschied machen, wenn der Code "unsigned char x = x;" gewesen wäre? [C11 6.2.6.2 1] – chux

+0

Das ist alles in Ordnung, aber es vermeidet das Problem. Sie können die selbstreferenzielle Initialisierung verwenden, um zirkuläre Listen zu erstellen, zum Beispiel: 'struct node {int value; Strukturknoten * next, * prev;} x = (Strukturknoten) {argc, & x, &x}; '. Soweit ich weiß, ist das legal und bringt das erwartete Ergebnis. – rici

+0

@chux: Ich glaube nicht. 6.3.2.1p2 gilt weiterhin. –

1
int x = x; 

ist Ursache für undefiniertes Verhalten. Zählen Sie nicht auf vorhersehbares Verhalten.

+0

Jeder Hinweis auf den Standard, der dies zeigen würde? Ich stimme dir zu, dass es intuitiv undefiniert ist. Es wäre jedoch schön, eine autoritative Quelle zu haben. – Sjlver

+1

Es ist die Lvalue to Rvalue-Konvertierung, die UB ist, da der Wert unbestimmt ist. –

+0

@Sjlver, ich konnte nichts mehr finden als was dasblinkenlicht zitiert. –

1

Clang darüber warnt:

$ clang -c -Wall ub_or_not_ub.c 
ub_or_not_ub.c:4:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized] 
    int x = x; 
     ~ ^

Also ich denke, es ist nicht definiertes Verhalten.

+1

Das ist eine gute Schätzung, aber es ist immer noch eine Vermutung. –

2

Nach der Sprachspezifikation

6.7.8.10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

Weiter sagt er

6.7.8.11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion).

Daher wird der Wert des initializer Ausdruck (x rechts von =) ist unbestimmt, so dass wir haben mit undefiniertem Verhalten zu tun, weil der Initialisierer aus der Variablen x mit einem unbestimmten Wert liest.

Verschiedene Compiler bieten Warneinstellungen, um solche Bedingungen zu erfassen.

+0

Sie haben den Teil verpasst, der zu undefiniertem Verhalten führt. –

+0

@DavidSchwartz - wäre nicht "sein Wert unbestimmt" gleich UB? – KevinDTimm

+0

@KevinDTimm Nicht sofort. Einen unbestimmten Wert zu haben ist kein UB, solange Sie ihn nicht vor einer Aufgabe lesen. Deshalb habe ich die Antwort bearbeitet, um Davids Punkt zu klären. – dasblinkenlight

Verwandte Themen