简体   繁体   中英

Why is using the value of int i; undefined behaviour but using the value of rand() is not?

If I don't initialise i , I don't know its value, but also I cannot predict the value of rand() .

But on the other hand, I know the value of the uninitialised i is between INT_MIN and INT_MAX , also I know the value of rand() is between 0 and RAND_MAX .

Why is using the value of the uninitialised i undefined behaviour but using the value of rand() is not?

The value of an uninitialized variable is undefined . The return value of rand() is well-defined as being the next number in the pseudo-random sequence for the given seed .

You can rely on rand() returning a pseudorandom number. You cannot rely on any characteristic of the value of an uninitialized int i .

I looked up the C99 standard (ISO/IEC 9899:1999), which is the only standard document I have available, but I seriously doubt these things have changed. In chapter 6.2.6 Representations of types , it is stated that integers are allowed to be stored in memory with padding bits , the value of which is unspecified but may include parity bits, which would be set upon initialization and any arithmetic operation on the integer. Certain representations (like eg a parity mismatch) could be trap representations , the behaviour of which is undefined (but might well terminate your program).

So, no, you cannot even rely on an uninitialized int i to be INT_MIN <= i <= INT_MAX .

The standard says reading from an uninitialized variable is undefined behaviour, so it is. You cannot say that it is between INT_MIN and INT_MAX . In fact, cannot really think of that variable as holding any value, so you couldn't even check that hypothesis * .

rand() on the other hand is designed to produce a random number within a range. If reading from the result of rand() were undefined, it wouldn't be part of any library because it couldn't be used.


* Usually "undefined behaviour" provides scope for optimization. The optimizer can do whatever it wants with an uninitialized variable, working under the assumption that it isn't read from.

Value of rand is defined to be (pseudo-)random. Value of an uninitialized variable is not defined to be anything. That is the difference, whether something is defined to be anything meaningful (while rand() is also meaningful - it gives (pseudo-)random numbers) or undefined.

The short answer, like others have said, is because the standard says so.

The act of accessing the value of a variable (described in the standard as performing an lvalue to rvalue conversion) that is uninitialised gives undefined behaviour.

rand() is specified as giving a value between 0 and RAND_MAX , where RAND_MAX (a macro declared in <cstdlib> for C++, and <stdlib.h> for C) is specified as having a value which is at least 32767 .

rand uses an algorithm to generate your number. So rand is not undefined and if when you use srand to start the random generation you choose a value like 42, you will always get the same value each time you launch your app try to launch this example you will see:

#include <stdio.h>
#include <stdlib.h>

int main()
{
  srand(42);

  printf("%d\n", rand());
  return 0;
}

see also: https://en.wikipedia.org/wiki/List_of_random_number_generators

Consider variable x in the following code:

uint32_t blah(uint32_t q, uint32_t r)
{
  uint16_t x;
  if (q)
    x=foo(q); // Assume return type of foo() is uint16_t
  if (r)
    x=bar(r); // Assume return type of bar() is uint16_t
  return x;
}

Since code never assigns x a value outside the range 0-65535, a compiler for a 32-bit processor could legitimately allocate a 32-bit register for it. Indeed, since the value of q is never used after the first time x is written, a compiler could use the same register to hold x has had been used to hold q . Ensuring that the function would always return a value 0-65535 would require adding some extra instructions compared with simply letting it return whatever happened to be in the register allocated to x .

Note that from the point of view of the Standard authors, if the Standard isn't going to require that the compiler make x hold a value from 0-65535, it may as well not specify anything about what may happen if code tries to use x . Implementations that wish to offer any guarantees about behavior in such cases are free to do so, but the Standard imposes no requirements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM