I have been trying to understand of this following C-program:
#include <stdio.h>
int arr[] = {1,2,3,4};
int count;
int incr(){
return ++count;
}
int main(){
arr[count++]=incr();
printf("%d %d",count,arr[count]);
return 0;
}
The program gives 1 2 as output,what I am not gtting is why the value of count is 1 here and not 2 (since there are two increments)?
The order of evaluation of operands of = operator is unspecified in arr[count++]=incr(); and since both the operands are trying to modify the same global variable count the result would be different on different compilers depending upon the order of evaluation.
EDIT
Actually the behavior is undefined (which means anything can happen) because "the prior value of the variable count is not accessed (only) to determine the value to be stored."
incr() will return either 1 or 2. It depends on whether the implementation first increments count and then calls incr(), or whether it first calls incr() and then increments count.
Please note that this choice does not mean that behavior is undefined. Since before a function is entered, and after a function is left, there is a sequence point at each point, both increments we have here are separated by a sequence point, so that the increment in main, if it started to happen before the call, will be finished once entering incr(), and if it happens after incr() was called, will not have yet started until incr() has left.
We have multiple scenarios here:
First do the increment for count++, then call incr(). This will write 2 into arr[0].
First call incr(), then do the increment for count++. This will write 1 into arr[1].
So, count is always 2, and arr[count] is always 3 (it wasn't overwritten). So it should output 2 3, not 1 2.
I think that if you do the following, you have more options
int main(){
arr[++count]=incr();
printf("%d %d",count,arr[count]);
return 0;
}
Now, the value read from ++count can be different than count+1, because there is nothing that stops incr() to be called after incrementing count but before reading it. In this case we have
First do the increment for ++count, then call incr(), then read from count. This will write 2 into arr[2].
First do the increment for ++count, then read from count, and then call incr(). This will write 2 into arr[1].
First call incr(), then do the increment for ++count and read from it. This will write 1 into arr[2].
In this case, you can either have output 2 2 or 2 1 or 2 3.
Related
I represents the global variable i.e the name I represents same variable inside and outside the function. Fact is first called when I = 1, which is the first value written. This value is
passed to the function's dummy argument N. The same I is now given the initial value 2 by the DO loop inside Fact, but since it is greater than N, the DO loop is not executed, so I still has the value 2
when Fact returns to be printed in the main program. However, I is now incremented to 3 in the
DO loop in the main program, which is the value it has when the second call to Fact takes place.
PROGRAM Factorial
IMPLICIT NONE
INTEGER I
DO I = 1, 10
PRINT*, I, Fact(I)
END DO
CONTAINS
FUNCTION Fact( N )
INTEGER Fact, N, Temp
Temp = 1
DO I = 2, N
Temp = I * Temp
END DO
Fact = Temp
END FUNCTION
END
and Once it completes I goes from 2 to N where now N =3..Now the function must returns I =3 to main program such that next I should be 4 in Do loop of main program, but when compiled and run..it only shows factor for 3,5,7 and 9.....My question is why it skip 4 or 6 or 8.
After exiting a loop the control variable gets the value of the upper bound + 1. However, it is illegal to modify the value of a loop control variable and anything can happen if you manage to do that despite the compiler's checks. It is an undefined behaviour then.
Not only that, you are aliasing the global I by using it as I as N at the same time inside the function. The compiler can probably perform various optimizations assuming that they are distinct when in fact they refer to the same variable. The program is therefore again illegal and unpredictable.
Consider this example and try to compile it with different optimization levels. You will get different answers:
i = 1
call s(i)
contains
subroutine s(j)
do k = 1, 10
j = i + j
end do
print *, j
end
end
Try it online!
This particular problem can probably be fixed by declaring i or the dummy argument target.
Consider simple code:
#include "stdio.h"
#define N 10U
int main() {
int a[N] = {0};
unsigned int i = N;
int s = 0;
// Fill a
while(i--)
s += a[i];
printf("Sum is %d\n", s);
return 0;
}
Does while loop contain undefined behavior because of integer underflow? Do compilers have right to assume that while loop condition is always true because of that and end up with endless loop?
What if i is signed int? Doesn't it contain pitfalls related to array access?
Update
I run this and similar code many times and it worked fine. Moreover, it's popular way to iterate over arrays and vectors backwards. I'm asking this question to make sure that this way is OK from point of view of standard.
At glance, it's obviously not infinite. On other hand, sometimes compiler can "optimize" away some conditions and code assuming that code contains no undefined behavior. It can lead to infinite loops and other unwanted consequences. See this.
This code doesn't invoke undefined behavior. The loop will be terminated once i becomes 0.
For unsigned int, there is no integer over/underflow. The effect will be same with i as signed except there will no wrapping in this case.
Does while loop contain undefined behavior because of integer underflow?
No, overflow/underflow is only undefined behavior in case of signed integers.
Do compilers have right to assume that while loop condition is always true because of that and end up with endless loop?
No, because the expression will eventually turn out to be zero.
What if i is signed int? Doesn't it contain pitfalls related to array access?
If it is signed and over/underflows, you invoke undefined behavior.
The loop does not yield undefined behaviour for the following reasons.
i is initialised to 10, and decremented in the loop. When i has a value of zero, decrementing it produces a value equal to UINT_MAX - the largest value an unsigned can represent, but the loop will terminate. a[i] will only ever be accessed (within the loop) for values of i between N-1 (i.e. 9) and 0. Those are all valid indices in array a.
s and all the elements of a are initialized to zero. So all the additions add 0 to 0. That will never overflow nor underflow an int, so can never result in undefined behaviour.
If i is changed to signed int, the decrementing never underflows, and i will have a negative value when the loop terminates. The only net change is in the value that i has after the loop.
i will wrap around to ~0 (0XFFFFFFFF for 32 bits) but the loop will terminate so there is no UB.
Your code is well-behaved and contains no undefined behavior for any value of N ≥ 0.
Let us focus on the while-loop, and trace through an execution example with N = 2.
// Initialization
#define N 2U
unsigned int i = N; // i = 2
// First iteration
while(i--) // condition = i = 2 = true; i post-decremented to 1
s += a[i]; // i = 1 is in bounds
// Second iteration
while(i--) // condition = i = 1 = true; i post-decremented to 0
s += a[i]; // i = 0 is in bounds
// Third iteration
while(i--) // condition = i = 0 = false; i post-decremented to 0xFFFFFFFF
// Loop terminated
We can see from this trace that a[i] is always in bounds, and i experiences an unsigned wraparound when decrementing from 0, which is perfectly well-defined.
To answer your second question, if we changed the type of i to signed int, the only behavior that changes in the example trace is that the loop terminates at the same place but i gets decremented to -1, which is also perfectly well-defined.
Thus in conclusion, your code is well-behaved assuming that N ≥ 0, whether i is unsigned int or signed int. (If N is negative and i is signed int, then the loop will keep decrementing until undefined behavior happens at INT_MIN.)
Does while loop contain undefined behavior because of integer underflow?
First off this is a Boolean Conversion:
A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool.
The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.
So there will be no integer underflow if i is properly initialized, it will reach 0U and that will be cast to a false value.
So what the compiler is effectively doing here is: while(static_cast<bool>(i--))
Do compilers have right to assume that while loop condition is always true because of that and end up with endless loop?
The key reason this isn't an endless loop is that the postfix decrement operator returns the value of the decremented variable. It's defined as T operator--(T&, int) And as discussed in previously the compiler is going to evaluate whether that value is 0U as part of the conversion to bool.
What the compiler is effectively doing here is: while(0 != operator--(i, 1))
In your update you cite this code as a motivation for your question:
void fn(void)
{
/* write something after this comment so that the program output is 10 */
int a[1] = {0};
int j = 0;
while(a[j] != 5) ++j; /* Search stack until you find 5 */
a[j] = 10; /* Overwrite it with 10 */
/* write something before this comment */
}
Upon inspection, that entire program has undefined behavior there is only 1 element of a and it's initialized to 0. So for any index other than 0, a[j] is looking off the end of the array. The will continue till a 5 is found or until the OS errors because the program has read from protected memory. This is unlike your loops condition which will exit when the postfix decrement operator returns a value of 0, so there can't be an assumption that this is always true, or that the loop will go on infinitely.
What if i is signed int?
Both of the above conversions are built-in to C++. And they are both defined for all integral types, signed and unsigned. So ultimately this expands to:
while(static_cast<bool>(operator--(i, 1)))
Doesn't it contain pitfalls related to array access?
Again this is calling a built-in operator, the subscript operator: T& operator[](T*, std::ptrdiff_t)
So a[i] is the equivalent of calling operator(a, static_cast<ptrdiff_t>(i))
So the obvious followup question is what's a ptrdiff_t? It's a implementation defined integer, but as such each implementation of the standard is responsible for defining conversions to and from this type, so i will cast correctly.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
Undefined Behavior and Sequence Points
Ok we all know that i++ increments value by 1 on next line and ++i increments on same line(please correct me if i am wrong there ) so for a sample statement of c as follows:
int a=0;
printf("%d , %d",++a,a);
the expected output should be 1 , 1 but instead it gives 1 , 0
so as one might guess what i am asking here is why does the second linking of
i print 0 instead of 1 when the value is already incremented.
So if post increment didn't increment value in the same line then what is the
difference between post and pre increment? edit : changed the name of variable from i to a to avoid grammatical confusion.
You are very wrong in your understanding of the increment operators.
i++ increments i, and returns its old value; ++i increments i,
and returns the new value. When the actual incrementation takes place
is only guaranteed to be after the preceding sequence point, and before
the next; in your code, this means before the call to printf.
Beyond that (and largely because of that), if you modify the value of an
object, you're not allowed to access it anywhere else without an
intervening sequence point, except as needed to determine the new value.
You violate this rule, so your code has undefined behavior.
It's undefined behavior. the compiler is allowed to calculate the parameters in any order. your compiler just calculate it from right to left, so the rightest parameter is 0, and the 2nd is 1.
edit: as Seth said, the compiler is only free to change the order of calculating, not to do whatever it wants, so when you don't care about the order you can freely call functions, but you should never assume that one parameter is been calculated before another.
I think your question is not about how increment work. The phenomenon you have observed is about the order of passing parameter to a function. As far as I can remember, this is not defined by c++ standard, so it's a UNDEFINED BEHAVIOR. Meaning different compiler could have different implementation.
E.g.
One compiler could pass parameter from left to right, then a different could pass parameters from right to left.
You can have a better read of Sequence point here:
http://en.wikipedia.org/wiki/Sequence_point
printf("%d , %d",++i,i);
is undefined behavior.
Your are violating C sequence points rule:
(C99, 6.5p2) "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored."
Once I read in some book that when a statement is like this:
printf("%d , %d",++a,a);
The execution starts from right to left but outputted as left to right. Therefore you see the out as 1 0 - 'a' is calculated first = 0 then '++a' = 1, but displayed as 1 0
This is strange but yeah that's how it works.
Hope this helps.
What is the output of the following code:
int main() {
int k = (k = 2) + (k = 3) + (k = 5);
printf("%d", k);
}
It does not give any error, why? I think it should give error because the assignment operations are on the same line as the definition of k.
What I mean is int i = i; cannot compile.
But it compiles. Why? What will be the output and why?
int i = i compiles because 3.3.1/1 (C++03) says
The point of declaration for a name is immediately after its complete declarator and before its initializer
So i is initialized with its own indeterminate value.
However the code invokes Undefined Behaviour because k is being modified more than once between two sequence points. Read this FAQ on Undefined Behaviour and Sequence Points
int i = i; first defines the variable and then assigns a value to it. In C you can read from an uninitialized variable. It's never a good idea, and some compilers will issue a warning message, but it's possible.
And in C, assignments are also expressions. The output will be "10", or it would be if you had a 'k' there, instead of an 'a'.
Wow, I got 11 too. I think k is getting assigned to 3 twice and then once to 5 for the addition. Making it just int k = (k=2)+(k=3) yields 6, and int k = (k=2)+(k=4) yields 8, while int k = (k=2)+(k=4)+(k=5) gives 13. int k = (k=2)+(k=4)+(k=5)+(k=6) gives 19 (4+4+5+6).
My guess? The addition is done left to right. The first two (k=x) expressions are added, and the result is stored in a register or on the stack. However, since it is k+k for this expression, both values being added are whatever k currently is, which is the second expression because it is evaluated after the other (overriding its assignment to k). However, after this initial add, the result is stored elsewhere, so is now safe from tampering (changing k will not affect it). Moving from left to right, each successive addition reassigns k (not affected the running sum), and adds k to the running sum.
Again, a silly question.
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int i = 0;
i = i++;
cout<<i;
return 0;
}
I get 1 printed as a result of this program though I expected 0: first a temp object created eing equal 0, then i is incremented, then temp object is returned and assigned to i. Just according to:
5.2.6 Increment and decrement [expr.post.incr]
1 The value obtained
by applying a postfix ++ is the value
that the operand had before applying
the operator. [Note: the value
obtained is a copy of the original
value ]
I checked it under MS VC 2008 and GCC. They give both the same result, though at least gcc issues a warning in incrementation string. Where am I wrong?
The behavior of
i = i++;
is undefined. If a single expression assigns two different values to a variable, the C++ spec says that anything can happen - it could take on its old value, one of the two new values, or pretty much anything at all. The reason for this is that it allows the compiler to make much more aggressive optimizations of simple expressions. The compiler could rearrange the order in which the assignment and ++ are executed, for example, if it thought it were more efficient.