这是未定义的行为,你如何判断

Is this undefined behavior and how would you tell?

本文关键字:何判断 判断 未定义      更新时间:2023-10-16

被这篇文章的回复所激励。为什么是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的适当动作?如何从编译器输出告诉它是未定义的行为?

谢谢。

是的,标准明确规定未初始化对象的左值到右值转换将导致未定义的行为:

非函数、非数组类型T的glvalue(3.10)可以转换为右值。如果T是不完全类型,则需要进行这种转换的程序是病态的。如果glvalue所指向的对象不是T类型的对象,也不是T派生类型的对象,或者该对象未初始化,则需要进行这种转换的程序具有未定义行为。

任何需要使用object的值的操作都将调用左值到右值的转换。

未定义行为定义为:

本国际标准未规定的行为

所以,是的,具有未定义行为的程序可以做任何事情,即使它看起来工作正常。因此,您不能总是从程序输出中识别未定义的行为。真正的解决方案是编写正确的、定义良好的代码。要做到这一点,我强烈建议您身边有一份c++标准的副本。编写代码并对其功能进行假设是一件非常糟糕的事情,所以如果你编写了任何你不确定的c++,一定要检查它。

为什么标准中存在未定义的行为?首先,这意味着你只会得到你想要的。如果将未初始化的变量定义为自动获取值0(例如),则您声明的每个未初始化的变量都将进行一些可能不需要的额外操作来将值设置为0。该标准简单地说,使用未初始化变量的值是未定义的,允许它在该内存位置留下已经存在的垃圾值。不额外收费。

其次,它允许编译器基于任何c++程序员都会编写相同的、定义良好的代码的假设来进行优化。

未定义行为就是这个意思。行为是未定义的。有些编译器会很好地警告你,有些则会做一些疯狂的事情。理论上,他们允许在这种情况下擦除你的硬盘驱动器,但这将是一个相当糟糕的编译器。

更具体地说,未初始化的变量可以有任何值。实际上,如果您的程序刚刚启动(操作系统提供的一种安全特性,用于阻止您的程序从旧程序中读取内存),它通常为0,但是一旦它运行了一段时间,它很有可能是一个完全随机的值,因为内存以前被另一个函数使用过。因此发出了警告。如果您忽略它,您的程序将随机失败,没有明显的原因。