1

Playing with randomness in C++, I have this piece of code:

 #include <iostream>

 // do not initialize return
 int   rand_int(){}
 float rand_float(){}

 int main(int argc, const char *argv[])
 {
   std::cout << rand_int()   << std::endl; // Ok, Garbage value
   std::cout << rand_float() << std::endl; // Always 0
   return 0;
 }

And as shown in the comment, there is a behavior I do not fully understand. With my gcc 6.4 (and no optimization flags), the rand_int function return garbage values on each call (ok), but the rand_float seems to return 0 on each call. I don't really understand why, as there is no initialization on the rand_float function.

Charles Gueunet
  • 1,708
  • 14
  • 14
  • Undefined behavior is undefined. The compiler may choose to return 0, or garbage, or crash, or any number of other things. You should enable your compiler warnings to catch cases like this where you aren't returning a value. – 0x5453 Mar 05 '18 at 16:53
  • I get 0 and 0. What happens when you reverse the calls? – Zebrafish Mar 05 '18 at 16:56
  • 1
    @Praetorian, I do not understand why you mark this question as duplicate. The duplicate you cite does not talk about float, which is the main point of this question. – Charles Gueunet Mar 05 '18 at 17:23
  • 1
    @Praetorian: Additionally, that asks whether it is okay for the compiler to return garbage, to which the answer is yes. This question asks why the OP is observing what they observe. They are different questions with different answers. – Eric Postpischil Mar 05 '18 at 17:32
  • 1
    @CharlesGueunet Well, as far as the C++ standard is concerned, there's nothing special about float and the linked duplicate answers your question. Anyway, I've reopened the question since you've found a satisfactory answer. – Praetorian Mar 05 '18 at 19:01

3 Answers3

2

First Undefined Behaviour just means that behaviour is undefined per standard, so a specific implementation can just do what it wants, from immediate program crash to reasonable processing.

I assume that your implementation uses the processor accumulator to return an int value, and the floating point coprocessor one to return a float value. As the accumulator is used for plenty of reasons and has no reason to be implicitely saved, you can expect garbage or more exactly hard to predict data in it. On the other hand, your implementation seems to initialize the floating point stack to 0 and you get that value. Simply you cannot rely on that: a different compiler or a different version of same compiler or even different compilation options could lead to a different result. It could even happen that the exact same compilation at a different time will give different results...

TL/DR: UB means that you can get anything...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
2

The C++ standard does not define the behavior when execution flows off the end of a function that is declared to return a value (other than main, which is special). So the behavior is a consequence of things on your particular computing platform.

First, it should be noted that any behavior not defined by the C++ standard is subject to changes during optimization by the compiler. The compiler may alter your program in radical ways, and the changes may differ drastically even with slight changes in compiler switches, source code, or other factors.

That said, processors commonly have separate registers for integer data and for floating-point data. Before your process enters the main routine, it executes some startup code that prepares the stack and various environmental states. As that code completes, it will leave its data in registers (since it has no reason to erase it), including the register that is assigned to hold the return value of a function call. When you print the result of rand_int(), you may be seeing some data leftover in that register.

The startup code may have no reason to use the floating-point registers, so it might not put any data in them. When you print the result of rand_float(), you may be seeing zero because the operating system initialized the floating-point registers to zero when it created your process.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

This function signature:

int rand_int();

Is advertising a contract. It is saying "I will return an int".

The implementation does not do what the interface claims. Thus you have undefined behaviour, which means that the returned value cannot be predicted. Indeed, it cannot be assumed that the object returned has been initialised at all. Thus to call this function renders the behaviour of the entire program undefined.

One might argue that this obvious logic error should generate a compiler error. I have made that case to the iso-cpp mailing list before, as have others. Bizarrely (to me), quite a number of c++ contributors seem to disagree with me.

Microsoft do not disagree. In MSVC, this is an error.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142