Variable initialization with itself - c++

Is it safe to write such code?
#include <iostream>
int main()
{
int x = x-x;// always 0
int y = (y)? y/y : --y/y // always 1
}
I know there is undefined behaviour, but isn't it in this case just a trash value? If it is, then same value minus same is always 0, and same value divided by itself (excluding 0) is always 1. It's a great deal if one doesn't want to use integer literals, isn't it? (to feint the enemy)

Allow me to demonstrate the evil magic of undefined behaviour:
given:
#include <iostream>
int main()
{
using namespace std;
int x = x-x;// always 0
int y = (y)? y/y : --y/y; // always 1
cout << x << ", " << y << endl;
return 0;
}
apple clang, compile with -O3:
output:
1439098744, 0
Undefined is undefined. The comments in the above code are lies which will confound future maintainers of your random number generator ;-)

I know there is undefined behaviour, but isn't it in this case just a trash value? If it is, then same value minus same is always 0, and same value divided by itself (excluding 0) is always 1.
No! No, no, no!
The "trash value" is an "indeterminate value".
Subtracting an indeterminate value from itself does not yield zero: it causes your program to have undefined behaviour ([C++14: 8.5/12]).
You cannot rely on the normal rules of arithmetic to "cancel out" undefined behaviour.
Your program could travel back in time and spoil Game of Thrones/The Force Awakens/Supergirl for everyone. Please don't do this!

Undefined behavior is undefined. Always. Stuff may work or break more or less reliably on certain platforms, but in general, you can not rely on this program not crashing or any variable having a certain value.

Undefined behavior is undefined behavior. There's no "isn't it in this case something specific" (unless you are actually talking about result of a completed compilation, and looking at the generated machine code, but that is no longer C++). Compiler is allowed to do whatever it pleases.

Related

Same array giving garbage value at one place and an unrelated value at the other place

In the following code:
#include<iostream>
using namespace std;
int main()
{
int A[5] = {10,20,30,40,50};
// Let us try to print A[5] which does NOT exist but still
cout <<"First A[5] = "<< A[5] << endl<<endl;
//Now let us print A[5] inside the for loop
for(int i=0; i<=5; i++)
{
cout<<"Second A["<<i<<"]"<<" = "<<A[i]<<endl;
}
}
Output:
The first A[5] is giving different output (is it called garbage value?) and the second A[5] which is inside the for loop is giving different output (in this case, A[i] is giving the output as i). Can anyone explain me why?
Also inside the for loop, if I declare a random variable like int sax = 100; then A[5] will take the value 100 and I don't have the slightest of clue why is this happening.
I am on Windows, CodeBlocks, GNUGCC Compiler
Well you invoke Undefined Behaviour, so behaviour is err... undefined and anything can happen including what your show here.
In common implementations, data past the end of array could be used by a different element, and only implementation details in the compiler could tell which one.
Here your implementation has placed the next variable (i) just after the array, so A[5] is an (invalid) accessor for i.
But please do not rely on that. Different compilers or different compilation options could give a different result. And as a compiler is free to assume that you code shall not invoke UB an optimizing compiler could just optimize out all of your code and only you would be to blame.
TL/DR: Never, ever try to experiment UB: anything can happen from a consistent behaviour to an immediate crash passing by various inconsistent outputs. And what you see will not be reproduced in a different context (context here can even be just a different run of same code)
In your Program, I think "there is no any syntax issue" because when I execute this same code in my compiler. Then there is no any issue likes you.
It gives same garbage value at direct as well as in loop.
enter image description here
The problem is that when you wrote:
cout <<"First A[5] = "<< A[5] << endl<<endl;//this is Undefined behavior
In the above statement you're going out of bounds. This is because array index starts from 0 and not 1.
Since your array size is 5. This means you can safely access A[0],A[1],A[2],A[3] and A[4].
On the other hand you cannot access A[5]. If you try to do so, you will get undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.
So the output that you're seeing is a result of undefined behavior. And as i said don't rely on the output of a program that has UB.
So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.
For the same reason, in your for loop you should replace i<=5 with i<5.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.

How are these two pieces of code different?

I tried these lines of code and found out shocking output. I am expecting some reason related to initialisation either in general or in for loop.
1.)
int i = 0;
for(i++; i++; i++){
if(i>10) break;
}
printf("%d",i);
Output - 12
2.)
int i;
for(i++; i++; i++){
if(i>10) break;
}
printf("%d",i);
Output - 1
I expected the statements "int i = 0" and "int i" to be the same.What is the difference between them?
I expected the statements "int i = 0" and "int i" to be the same.
No, that was a wrong expectation on your part. If a variable is declared outside of a function (as a "global" variable), or if it is declared with the static keyword, it's guaranteed to be initialized to 0 even if you don't write = 0. But variables defined inside functions (ordinary "local" variables without static) do not have this guaranteed initialization. If you don't explicitly initialize them, they start out containing indeterminate values.
(Note, though, that in this context "indeterminate" does not mean "random". If you write a program that uses or prints an uninitialized variable, often you'll find that it starts out containing the same value every time you run your program. By chance, it might even be 0. On most machines, what happens is that the variable takes on whatever value was left "on the stack" by the previous function that was called.)
See also these related questions:
Non-static variable initialization
Static variable initialization?
See also section 4.2 and section 4.3 in these class notes.
See also question 1.30 in the C FAQ list.
Addendum: Based on your comments, it sounds like when you fail to initialize i, the indeterminate value it happens to start out with is 0, so your question is now:
"Given the program
#include <stdio.h>
int main()
{
int i; // note uninitialized
printf("%d\n", i); // prints 0
for(i++; i++; i++){
if(i>10) break;
}
printf("%d\n", i); // prints 1
}
what possible sequence of operations could the compiler be emitting that would cause it to compute a final value of 1?"
This can be a difficult question to answer. Several people have tried to answer it, in this question's other answer and in the comments, but for some reason you haven't accepted that answer.
That answer again is, "An uninitialized local variable leads to undefined behavior. Undefined behavior means anything can happen."
The important thing about this answer is that it says that "anything can happen", and "anything" means absolutely anything. It absolutely does not have to make sense.
The second question, as I have phrased it, does not really even make sense, because it contains an inherent contradiction, because it asks, "what possible sequence of operations could the compiler be emitting", but since the program contains Undefined behavior, the compiler isn't even obliged to emit a sensible sequence of operations at all.
If you really want to know what sequence of operations your compiler is emitting, you'll have to ask it. Under Unix/Linux, compile with the -S flag. Under other compilers, I don't know how to view the assembly-language output. But please don't expect the output to make any sense, and please don't ask me to explain it to you (because I already know it won't make any sense).
Because the compiler is allowed to do anything, it might be emitting code as if your program had been written, for example, as
#include <stdio.h>
int main()
{
int i; // note uninitialized
printf("%d\n", i); // prints 0
i++;
printf("%d\n", i); // prints 1
}
"But that doesn't make any sense!", you say. "How could the compiler turn "for(i++; i++; i++) ..." into just "i++"? And the answer -- you've heard it, but maybe you still didn't quite believe it -- is that when a program contains undefined behavior, the compiler is allowed to do anything.
The difference is what you already observed. The first code initializes i the other does not. Using an unitialized value is undefined behaviour (UB) in c++. The compiler assumes UB does not happen in a correct program, and hence is allowed to emit code that does whatever.
Simpler example is:
int i;
i++;
Compiler knows that i++ cannot happen in a correct program, and the compiler does not bother to emit correct output for wrong input, hece when you run this code anything could happen.
For further reading see here: https://en.cppreference.com/w/cpp/language/ub
The is a rule of thumb that (among other things) helps to avoid uninitialized variables. It is called Almost-Always-Auto, and it suggests to use auto almost always. If you write
auto i = 0;
You cannot forget to initialize i, because auto requires an initialzer to be able to deduce the type.
PS: C and C++ are two different languages with different rules. Your second code is UB in C++, but I cannot answer your question for C.

Function with no return statement but compiled and returned right answer

In the section of the code below, there is no return statement in the function but it still compiled and gave the right answer. Is this a normal behavior?
#include <iostream>
int multiply (int x, int y) {
int product = x * y;
}
int main (int argc, char **argv) {
std::cout << multiply(4, 5) << std::endl;
return 0;
}
No, getting the correct answer from the function is not normal behaviour, it's a coincidence. You should not rely on this.
From C++03, 6.6.3 The return statement /2 (and the same section for C++11 as well):
Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
You'll probably find that you're getting the correct answer simply because of the side effects of your calling convention.
For example, if a function value is returned in the (mtyhical) r0 register, it may be that the calculation uses that register within the function to hold the value, before storing it into the memory representing the product variable. So the fact it's in r0 when you return is just a hang-over from the way things are done.
Compiling with different levels of optimisation, or using another compiler, or even compiling on a Tuesday evening during a blue moon may affect the outcome, that's the main problem with undefined behaviour - it's untrustworthy. At a bare minimum, a good compiler would have warned you about this.

What can happen if printf is called with a wrong format string?

Or in other words: Could a wrong printf / fprintf decimal integer (%d, %u, %ld, %lld) format string cause a program to crash or lead to undefined behavior?
Cosinder following lines of code:
#include <iostream>
#include <cstdio>
int main() {
std::cout << sizeof(int) << std::endl
<< sizeof(long) << std::endl;
long a = 10;
long b = 20;
std::printf("%d, %d\n", a, b);
return 0;
}
Result on 32 bit architecture:
4
4
10, 20
Result on 64 bit architecture:
4
8
10, 20
In any case the program prints the expected result. I know, if the long value exceeds the int range, the program prints wrong numbers – which is ugly, but doesn't effect the main purpose of the program –, but beside this, could anything unexpected happen?
What can happen if printf is called with a wrong format string?
Anything can happen. It is Undefined behavior!
Undefined behavior means that anything can happen. It may show you results which you expect or it may not or it may crash. Anything can happen and you can blame no one but yourself about it.
Reference:
c99 Standard: 7.19.6.1:
para 9:
If a conversion specification is invalid, the behavior is undefined.225) If any argument is
not the correct type for the corresponding coversion specification, the behavior is
undefined.
It's undefined behaviour - there is nothing in the specification telling the compiler designer (or C library designer) how this should be handled, and thus they are allowed to do anything.
In practice, is one of those where it's entirely up to the interpretation of the numbers, and most likely, you won't ever get anything GOOD from doing this. The really bad ones are when you mix string with integer formatting - strings will print nicely as (strange, perhaps) numbers, but numbers are unlikely to "work" when passed as strings - because a string is a pointer to the address of the first character - and most numbers are not valid pointers in a typical system, so it will crash.
But there is no guarantee of anything. In your 64-bit example, it's clear that the number is "little endian". Try the same thing with 0x100000000, and it will print 0 - because the rest of the number is lost.
Oh yes - printf depends on the format string to determine the size and type of the variable to fetch next. When the format string is wrong it may try to fetch a variable that isn't even there, with all consequences that may have.
Anything can happen if printf is called with a wrong format string . Its undefined behaviour and one should never rely on undefined behaviour.
Don't use printf
printf is a relic of the C days, and is no longer needed... Use std::cout and I/O manipulators instead.

How disastrous is integer overflow in C++?

I was just wondering how disastrous integer overflow really is. Take the following example program:
#include <iostream>
int main()
{
int a = 46341;
int b = a * a;
std::cout << "hello world\n";
}
Since a * a overflows on 32 bit platforms, and integer overflow triggers undefined behavior, do I have any guarantees at all that hello world will actually appear on my screen?
I removed the "signed" part from my question based on the following standard quotes:
(§5/5 C++03, §5/4 C++11) If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.
(§3.9.1/4) Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer. This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.
As pointed out by #Xeo in the comments (I actually brought it up in the C++ chat first):
Undefined behavior really means it and it can hit you when you least expect it.
The best example of this is here: Why does integer overflow on x86 with GCC cause an infinite loop?
On x86, signed integer overflow is just a simple wrap-around. So normally, you'd expect the same thing to happen in C or C++. However, the compiler can intervene - and use undefined behavior as an opportunity to optimize.
In the example taken from that question:
#include <iostream>
using namespace std;
int main(){
int i = 0x10000000;
int c = 0;
do{
c++;
i += i;
cout << i << endl;
}while (i > 0);
cout << c << endl;
return 0;
}
When compiled with GCC, GCC optimizes out the loop test and makes this an infinite loop.
You may trigger some hardware safety feature. So no, you don't have any guarantee.
Edit:
Note that gcc has the -ftrapv option (but it doesn't seem to work for me).
There are two views about undefined behavior. There is the view it is there to gather for strange hardware and other special cases, but that usually it should behave sanely. And there is the view that anything can happen. And depending on the UB source, some hold different opinions.
While the UB about overflow has probably been introduced for taking into account hardware which trap or saturate on overflow and the difference of result between representation, and so one can argue for the first view in this case, people writing optimizers hold very dearly the view that if the standard doesn't guarantee something, really anything can happen and they try to use every piece of liberty to generate machine code which runs more rapidly, even if the result doesn't make sense anymore.
So when you see an undefined behavior, assume that anything can happen, however reasonable a given behavior may seem.