taocp
taocp

Reputation: 23624

Is this undefined behavior and how would you tell?

Motivated by answers to this post. Why is this NaN

I have the following code:

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;
}

It will output the following:

a = 0
0
0

Under gcc 4.5.3, with compiling option -Wall.

I also compiled the code under here: http://liveworkspace.org/code/94SOj$2. Same output as above.

I also compiled the code under VS2010. VS2010 gaves warning as follows:

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

When I ran:

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

I know that it is bad practice to NOT initialize local variable and use them. I also understand it will be problematic.

My question is:

In C++ standard: is there any place saying that using uninitialized local variable will result in undefined behavior? Why does it behave differently under different compilers? Does this mean the standard actually does not enforce that all compilers should implement proper actions regarding using uninitialized local variable? How would you tell it is undefined behavior from compiler output then?

Thanks.

Upvotes: 0

Views: 117

Answers (2)

Joseph Mansfield
Joseph Mansfield

Reputation: 110648

Yes, the standard explicitly says that lvalue-to-rvalue conversion on an uninitialized object will result in undefined behaviour:

A glvalue (3.10) of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

Anything that requires using the value of object will invoke lvalue-to-rvalue conversion.

Undefined behavior is defined as:

behavior for which this International Standard imposes no requirements

So yes, a program with undefined behaviour can do anything, even if it appears to work correctly. So you cannot always identify undefined behaviour from a program's output. The real solution is to write correct, well-defined code. To do this, I highly recommend having a copy of the C++ standard by your side. Writing code and making assumptions about what it does is a very bad things, so if you ever write any C++ that you're not sure about, be sure to check it up.

Why does undefined behaviour exist in the standard? Firstly, it means you really only get what you ask for. If an uninitialized variable were instead defined to automatically get the value 0 (for example), every variable you declare that you don't initialize will have some extra operation to set the value to 0 that probably isn't needed. The standard simply says that using the value of an uninitialized variable is undefined, allowing it to leave the garbage value that already existed in that memory location. No extra cost.

Secondly, it allows the compiler to make optimizations based on the assumption that any C++ programmer will write sane, well-defined code.

Upvotes: 6

Dave
Dave

Reputation: 46249

Undefined behaviour means exactly that. The behaviour is undefined. Some compilers will be nice and warn you, others will do crazy things. In theory they're allowed to erase your hard drive in that situation, but that would be a pretty bad compiler.

To get specific, an uninitialised variable could have any value. In practice, it will usually be 0 if your program has only just started (a security feature provided by the OS to stop your program reading memory from old programs), but once it's been running for a while, there's a high chance it will be a totally random value because the memory was previously used by another function. Hence the warning. If you ignore it, your program will randomly fail for no apparent reason.

Upvotes: 1

Related Questions