4

私は少し混乱しています。私の知る限り、Cでintを初期化せずに宣言すると、たとえば次のようになります。int x;

したがって、その値は不定です。したがって、それを使用しようとすると、または未定義の動作が必要になります。

したがって、VS2010 で次のコードを実行すると、プログラムがクラッシュします。

int main(){
    int a;
    printf("%d\n",a);
    return 0;
}

次のコードを見てみましょう。このコードは警告を表示せず、クラッシュもしません(なぜ?)

void foo(int *var_handle){
    // do nothing
}

int main(){
    int a;
    foo(&a);
    printf("%d\n",a); // works, prints some big value
    return 0;
}

これの振る舞いを説明できますか?まったく何もしない関数への呼び出しを追加しただけですが、プログラムがクラッシュしなくなりました。

4

6 に答える 6

8

初期化されていない変数の値を読み取ると、未定義の動作が発生します。また、未定義の動作は、クラッシュする可能性があることを意味します。クラッシュするという意味でも、クラッシュする義務があるという意味でありません。

初期化されていない変数には値が指定されていません。その値が何であるかは不明です。したがって、実際には、適切な実装であれば、この種のコードはおそらくクラッシュすることはありません。変数を裏付ける有効なメモリアドレスがあり、ガベージコンテンツがあり、printf()問題なく読み取り、整数として解釈して出力します。それだけです。

于 2013-03-07T10:36:04.960 に答える
4

初期化されていない値を使用しても、未定義の動作が直接発生することはありません。

C 2011(n1570ドラフト)6.7.9 10によると、自動保存期間を持つ初期化されていないオブジェクトの値は不確定です。3.19.2 1によると、不確定な値は、不特定の値またはトラップ表現のいずれかです。同様のテキストがC1999に表示されます。

オブジェクトにトラップ表現がある場合、未定義の動作が発生する可能性があります。ただし、オブジェクトに不特定の値がある場合、オブジェクトに特定の値がある場合、プログラムはhasを動作させる必要があります。オブジェクトがどの値を持っているかは単に指定されていません。値が指定されていないという理由だけでプログラムがクラッシュすることは許可されていません。

Visual Studio 2010でタイプにトラップ表現が含まれているとは思わないため、Visual Studio2010でクラッシュが表示された単純なプログラムを報告するのは驚くべきことですint。予期したもの以外のソースファイルがコンパイルされてクラッシュしたか、初期化されていないオブジェクトを追跡しようとするVisualStudio2010の特別なデバッグ機能を有効にしていること(ただし、を使用する2番目のケースでは失敗しますfoo)。

この質問で表示したコードを新しいファイルに貼り付け、デフォルトのオプションを使用してその新しいファイルをコンパイルして、最初からテストを繰り返すことをお勧めします。

もちろん、Visual Studio 2010はC標準に準拠しておらず、古い1999標準にも準拠していないため、上記の条項に従う必要はありません。事実上、Visual Studio 2010に関するすべては、C標準に関して未定義の動作です。

于 2013-03-07T12:27:10.150 に答える
1

あなたはこれを試すことができます。それが厳密に未定義の動作であるかどうかはわかりませんが、コンパイラが実際に未定義の方法で動作し、少なくともfoo別のコンパイルユニットにある場合はC標準に準拠する方法を考えることはできません(〜ソースファイル)、コンパイラは未定義の動作を生成できることを認識していないためです;)。

void foo(int *var_handle){
    // do something to var_handle, or maybe nothing, who knows
}

int main(){
    int a[1];
    foo(a);
    printf("%d\n", a[0]);
    return 0;
}

編集:さらなる考え:

関数へのローカル変数への非定数ポインターを指定することにより、初期化されていないローカル変数を初期化するために関数を使用しても問題ないと確信しています。したがって、ローカル変数のアドレスを取得するだけで、コンパイラに関する限り、未定義の値を持つ定義済み変数になります。コンパイラは、関数が実際に値を設定しているかどうかを知ることができません(関数はライブラリにある可能性があります)。

しかし、これはクラッシュを回避する理由を説明しているにすぎません。関数をインライン化して何もしなかった場合でも、オプティマイザーは呼び出しを削除し、初期化されていないローカル変数の取得アドレスを削除して、「未定義動作」状態のままにすることができます。最適化を行い、アセンブリ出力から検証することで、コンパイラに対してこれをテストできます。その呼び出しfooはインライン化され(コードは生成されません)、printfがクラッシュするかどうかを確認します。

于 2013-03-07T12:10:51.233 に答える
1

これは未定義の動作です。つまり、何かが起こる可能性があります。文字通り何でも。動作は定義されていません。

于 2013-03-07T10:35:25.307 に答える
0

初期化されていない変数を使用すると、プログラムがクラッシュするという保証はありません。変数に割り当てられたメモリ位置に、どのジャンク データがたまたまあるかによって異なります。

于 2013-03-07T10:36:14.030 に答える