As far as I know (and I could be wrong), reading uninitialized memory in C is not UB, but gives an indeterminate value, which may be either an unspecified value or a trap representation. If it is a trap representation, accessing it is indeed UB, but if all possible values of your memory are valid, e.g. if you have an unpadded integer where every bit representation means something valid, then it is not UB, though it is still an unspecified value which does not even have to be consistent: you could get different values when reading the same uninitialized location twice.
Edit: Some excerpts from the C standard:
6.7.8 Initialization
10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.
3.17.2 indeterminate value
either an unspecified value or a trap representation
3.17.3 unspecified value
valid value of the relevant type where this International Standard imposes no requirements on which value is chosen in any instance
6.2.6 Representation of types
6.2.6.1 General
5 Certain object representations need not represent a value of the object type. … Such a representation is called a trap representation.
That says used, not read. And indeterminate, not unspecified. My point was on reading a value, not on acting on the value. I know it looks like nit-picking, and you should just not read uninitialized memory, but I don't think it's consistent with the standard to say that reading uninitialized memory is always UB.
What kind of read would not constitute "using" a value? And per your previous post an object that was not initialised is indeterminate, not just unspecified. So yes, reading uninitialized memory is always UB.
>Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. ... Such a representation is called a trap representation.
A read from uninitialized memory is not always UB.
What you quoted doesn't actually say anything about what happens when a trap representation is read into a character type. Such a read is still "using" the value at least in the everyday sense of the word, so in the absence of something explicitly to the contrary, as far as I can see the part of the standard that states that using an uninitialised value is UB stil applies.
Per http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_451.htm , the current standard is unclear in some respects, but the latest committee view is that that under the current standard any library function (including memcpy) may exhibit undefined behaviour when called with uninitialized memory, even when the uninitialized memory is of character type or is propagated through values of character type.
That is reading the uninitialized value twice. Since it is unspecified, it does not have to be consistent, so you could get the same behavior as non-zero for the first reading, and zero for the second reading. Changing your code to:
Unspecified values are constant (since they are values), just unspecified. This behaviour is only permitted because reading uninitialised memory is UB; you won't see the same thing if x is an unspecified value.
Only if there was UB, and the point is that there probably isn't. (I'm not really knowledgeable on the C standard, so I might have misinterpreted something.)
Making an "if" statement depend on the value of the uninitialized memory is an example of what is meant by using the value, and thus UB.
In the compiler discovers UB, the Standard places no requirements of any kind on the program or compiler. It is free to launch missiles, or (more likely) assume this code cannot be reached, and omit it from the program, along with any code that reaches it unconditionally, and any check that would send control that way. Such elision is the basis for many important optimizations.
Implementations are free to define things left undefined by Standards. For example, "#include <unistd.h>" is UB by the ISO Standard, but defined by Posix, which implementations also adhere to.
No. It is not "undefined behavior". The "behavior" here is assignment (reading memory). It always will behave precisely and consistently: it _will_ assign the "indeterminite" value of the un-initialized memory. Using such an "indeterminite value" in other operations (e.g comparison per the link Steve B. posted above: https://www.ralfj.de/blog/2019/07/14/uninit.html) is the UB bit.
> [reading memory} always will behave precisely and consistently
What is the point of not making it UB? You can't AFAICS possibly rely on any useful way on it behaving 'precisely and consistently' so just make it UB anyway?