11
int test[2] = { 45, test[0] };
int x = (x = 111);
cout << test[0] << " " << test[1] << " " << x << "\n"; // 45 45 111

最初の 2 行の割り当ては有効ですか? Visual Studio 2010 は、エラーや警告なしでコンパイルして実行しますが、未定義の可能性がある奇妙なケースのように思われるため、許容できることを確認したいと思いました。Visual Studio は、あからさまに再帰的 (そしておそらく未定義) のようなことをすると警告を発するint x = x;ので、許可されているように見えるこれらの状況がどのように処理されるのか疑問に思っています。

4

4 に答える 4

5

C++ 標準から (C++11 ですが、C++98/03 でも違いはありませんでした):

(§ 3.3.2/1)名前の宣言のポイントは、その完全な宣言子 (第 8 節) の直後、およびその初期化子(存在する場合) の前です [...] [例:

int x = 12;
{ int x = x; }

ここで、2 番目の x は独自の (不確定な) 値で初期化されます。—終わりの例]

これは、ユーザー定義型だけでなく配列型にも適用されます。x2 番目の例では不定値で初期化されていることを規格がどのように強調しているかに注意してください。したがって、初期化された値を知る方法はありませんx

于 2012-11-09T01:07:06.360 に答える
1

関数などを呼び出しているので、何らかの関数にいると思います。

testとの両方のスペースは、スタックxに割り当てられます。理論的には、値が入力される前にこれらの人のためのスペースが存在するはずです。生成されたアセンブリ (x86 gcc) を見ると、これは正しいです。

subl    $40, %esp         # Add 40 bytes of memory to the current stack
movl    $0, -20(%ebp)     # Clear test[0] to 0
movl    $0, -16(%ebp)     # Clear test[1] to 0
movl    $45, -20(%ebp)    # Place the value of 45 into test[0]
movl    -20(%ebp), %eax  # Copy that 45 into a register
movl    %eax, -16(%ebp)  # Move that register's value (45) into test[1]
movl    $111, -12(%ebp)  # Assign x to be 111, optimize out the unnecessary duplicate assignment
    ... #continues on to set up and call printf

スタックに 40 バイトが追加されていることがわかります。%ebptest[0]、test[1]、および x のアドレスはすべて、4 バイト間隔 (それぞれ -20、-16、-12) でマークされた連続したアドレスであることに注意してください。メモリ内のそれらの場所は存在し、定義される前にエラーなしでアクセスできます。ここでコンパイラは両方を 0 にクリアしますが、これは不要であることがわかります。これらの 2 行を削除しても問題なく実行できます。

ここから導き出せることは、あなたのint test[2]int xは、それ自体の中にファンキーな循環参照をいくつでも持つことができ、コードがコンパイルされるということです.あなたの仕事は、参照が適切なデータを確実に取得することです(つまり、何らかの方法で初期化されたデータ) )、ここで行ったガベージではありません。これは他のケースでも機能します - アセンブリにコンパイルし、それがどのように行われたかを自分で確認してください。

于 2012-11-09T02:57:24.560 に答える
0

変数の宣言は、初期化するまでに完了しているため、合法です。ただし、 の値test[1]は定義されていません。

于 2012-11-09T00:32:23.773 に答える
0

あなたが持っているすべてのコードは完全に合法です。あなたが実際にそれをしたいと思うかもしれない状況さえあります.

于 2012-11-09T00:32:35.180 に答える