2016-10-03 16 views
0

Cでは、宣言された同じステートメントで変数を使用できますか?同じステートメントで変数を宣言して使用する

次のプログラムがエラーなしでコンパイルされ、実行され、GCC 4.9と打ち鳴らす3.5の両方において:

#include "stdio.h" 

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

GCCにおいては0と打ち鳴らす32767に出力する(最大の正の2バイトの整数値です)。

なぜこれでコンパイルエラーは発生しませんか?これは特定のC仕様で有効ですか?その動作は明示的に未定義ですか?

+2

MSVCでは、「警告C4700:初期化されていないローカル変数 'x'が使用されました」を出力します。愚かな質問をする前に、コンパイラの警告を有効にしてください。 –

+1

@WeatherVane:コンパイラが警告を出しても、それが有効かどうかはわかりません。 –

+0

MSVCは実行時に '-1373317485'を出力します。まあ、いろいろな値。 –

答えて

4

これは、制約または構文ルールに違反しないという意味で "有効"なので、コンパイル時診断は不要です。名前xはイニシャライザ内に表示され、宣言されているオブジェクトを参照します。範囲はN1570 6.2.1パラグラフ7で定義されている:

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.

この場合宣言子int xあります。

これは、のようなものが可能になります:

int x = 10, y = x + 1; 

しかし、初期化子が初期化されていないオブジェクトを参照するための宣言は、未定義の動作をしています。

動作が未定義であるという明示的な記述は、左辺(オブジェクトを指定する式)をそのオブジェクトに格納された値に「変換」するN1570 6.3.2.1パラグラフ2にあります。

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.

問題のオブジェクトは、イニシャライザで参照されるxです。この時点では、xに値が割り当てられていないため、式には未定義の動作があります。

十分な警告レベルを有効にすると、実際にはコンパイル時の警告が表示されることがあります。

int x; 

それにカウントされません。実際の動作あなたが初期化子を省略した場合と同じであるかもしれません。

+0

コードが 'unsigned char x = x;'だった場合に違いはありますか? [C11 6.2.6.2 1] – chux

+0

それはすべて正しいですが、それは問題を回避します。自己参照初期化を使って循環リストを構築することができます。例えば、以下のようになります。 'struct node {int value; struct node * next、* prev;} x =(struct node){argc、&x、&x}; 'です。私が知る限り、それは合法であり、期待される結果を生む。 – rici

+0

@chux:そうは思わない。 6.3.2.1p2が適用されます。 –

1
int x = x; 

は未定義の動作の原因です。予測可能な行動を考慮しないでください。

$ 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; 
     ~ ^

だから私はそれは未定義の動作だと思う:

+0

これを示す標準への参照はありますか?私はあなたに直感的に同意します、それは未定義の行動です。しかし、権威のある情報源を持つことは良いことです。 – Sjlver

+1

左辺値と右辺値の変換は値が不定であるためUBです。 –

+0

@Sjlver、私はdasblinkenlightが引用したもの以外何も見つけることができませんでした。 –

1

クランはこれについて警告しません。

+1

それは良い推測ですが、それはまだ推測です。 –

2

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

また言語仕様によれば、

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).

したがって

、初期化式(=の右側x)の値不定であるので、我々は言います初期化子が不確定値を持つ変数xから読み込むため、未定義のビヘイビアが処理されています。

さまざまなコンパイラが、このような条件を捕まえるための警告設定を提供します。

+0

あなたは未定義の動作をさせる部分を見逃しました。 –

+0

@DavidSchwartz - その値は不定ではないでしょうか?UBと等しくなりますか? – KevinDTimm

+0

@KevinDTimmすぐには分かりません。あなたが割り当てに先立ってそれを読んでいない限り、不確定な値を持つことはUBではありません。だからこそ私はDavidのことを明確にするために答えを編集した。 – dasblinkenlight

関連する問題