0

この投稿への回答によって動機付けられました。なぜこれが NaN なのか

次のコードがあります。

int main()
{
   const int weeks = 10;
   const int salespersons = 9;
   const int days = 30;

   double weekly_sales[weeks][salespersons][days];
   double total_weekly_sales[weeks];
   double total_overall_weekly_sales[salespersons];
   int a;
   cout << "a = " << a <<endl;
   cout << total_weekly_sales[0] <<endl; 
   for(int w=0; w < weeks;w++)
   {
      for(int d =0; d < days; d++)
      {  
          for(int s=0; s < salespersons; s++)
          {
              total_weekly_sales[w]+=weekly_sales[w][s][d];
              total_overall_weekly_sales[s]+= weekly_sales[w][s][d];
          }
       }  
    }
 cout << total_weekly_sales[0] <<endl;
}

次のように出力されます。

a = 0
0
0

gcc 4.5.3 では、コンパイル オプション-Wall.

ここでコードもコンパイルしました: http://liveworkspace.org/code/94SOj $2. 上記と同じ出力。

また、VS2010 でコードをコンパイルしました。VS2010 では、次のような警告が表示されました。

warning C4700: uninitialized local variable 'a' used
warning C4700: uninitialized local variable 'total_weekly_sales' used

私が走ったとき:

Run-Time Check Failure #3 - The variable 'a' is being used without being initialized.

ローカル変数を初期化せずに使用するのは悪い習慣であることを知っています。問題になることも理解しています。

私の質問は:

C++ 標準: 初期化されていないローカル変数を使用すると未定義の動作になると言っている場所はありますか? 異なるコンパイラで異なる動作をするのはなぜですか? これは、すべてのコンパイラが適切なアクションを実装する必要があることを標準が実際に強制していないことを意味しますusing uninitialized local variableか? それでは、コンパイラ出力から未定義の動作であるとどのように判断できますか?

ありがとう。

4

2 に答える 2

6

はい、標準では、初期化されていないオブジェクトの左辺値から右辺値への変換は未定義の動作になると明示的に述べています。

非関数型、非配列型の glvalue (3.10) は、Tprvalue に変換できます。Tが不完全な型の場合、この変換を必要とするプログラムは形式が正しくありません。glvalue が参照するオブジェクトが T 型のオブジェクトでも、T から派生した型のオブジェクトでもない場合、またはオブジェクトが初期化されていない場合、この変換を必要とするプログラムの動作は未定義です。

オブジェクトの値を使用する必要があるものはすべて、左辺値から右辺値への変換を呼び出します。

未定義の動作は次のように定義されています。

この国際規格が要件を課していない行動

そうです、動作が未定義のプログラムは、たとえ正しく動作しているように見えても、何でもできます。したがって、プログラムの出力から未定義の動作を常に特定できるとは限りません。本当の解決策は、正しく明確に定義されたコードを記述することです。これを行うには、C++ 標準のコピーを手元に置くことを強くお勧めします。コードを書いて、それが何をするかを仮定するのは非常に悪いことなので、よくわからない C++ を書いたことがあれば、必ず調べてください。

標準に未定義の動作が存在するのはなぜですか? 第一に、それは本当にあなたが求めるものだけを手に入れることを意味します。代わりに、初期化されていない変数が値 0 を自動的に取得するように定義されている場合 (たとえば)、初期化しないことを宣言するすべての変数には、おそらく必要ない値を 0 に設定するための追加の操作があります。標準では、初期化されていない変数の値を使用することは未定義であり、そのメモリ位置に既に存在するガベージ値を残すことができると単純に述べています。追加料金なし。

第 2 に、C++ プログラマーは適切に定義された適切なコードを作成するという前提に基づいて、コンパイラーが最適化を行うことができます。

于 2013-04-04T19:48:14.787 に答える
1

未定義の動作はまさにそれを意味します。動作は未定義です。親切に警告してくれるコンパイラもあれば、おかしなことをするコンパイラもあります。理論的には、そのような状況でハードドライブを消去することは許可されていますが、それはかなり悪いコンパイラです.

具体的に言うと、初期化されていない変数は任意の値を持つことができます。実際には、プログラムが起動したばかりの場合 (プログラムが古いプログラムからメモリを読み取るのを停止するために OS によって提供されるセキュリティ機能)、通常は 0 になりますが、しばらく実行すると、高い可能性があります。メモリが以前に別の関数によって使用されていたため、完全にランダムな値。したがって、警告。これを無視すると、プログラムは明確な理由もなくランダムに失敗します。

于 2013-04-04T19:50:15.327 に答える