This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 8 years ago.
Kindly explain the output for the following code:
#include<stdio.h>
#include<stdlib.h>
#define SQUARE(x) (x*x*x)
int main() {
int x = 3;
int y = SQUARE(++x)/x++; // Undefined behavior even though it doesn't look
// like it here
printf("%d %d",x,y);
return 0;
}
Output: 7 25
Please explain how the value of y comes to be 25?
The macro is misnamed, but that's just a red herring. The two statements expand to:
int x = 3;
int y = (++x * ++x * ++x) / x++;
This is undefined behavior, since x is being modified more than once between sequence points. The compiler is allowed to do almost anything; it can interleave the uses of x and the pre- and post-increments of x almost anyway it wants. It can do things left-to-right, in which case, you get:
int y = (4 * 5 * 6) / 6;
Under this scheme, x is now 7 and y is now 20.
It could have done things right-to-left:
int y = (7 * 6 * 5) / 3;
Now, y is 70.
It could have cached the value of x at almost any point and used it. Try running your program under various compilers, with various optimization levels. Does gcc -O4 differ from cc? In fact, quoting the Internet Jargon file:
nasal demons: n.
Recognized shorthand on the Usenet group comp.std.c for any unexpected behavior of a C compiler on encountering an undefined construct. During a discussion on that group in early 1992, a regular remarked “When the compiler encounters [a given undefined construct] it is legal for it to make demons fly out of your nose” (the implication is that the compiler may choose any arbitrarily bizarre way to interpret the code without violating the ANSI C standard). Someone else followed up with a reference to “nasal demons”, which quickly became established. The original post is web-accessible at http://groups.google.com/groups?hl=en&selm=10195%40ksr.com.
So, I'd be a lot more careful here. Do you want demons flying out of your nose?
Related
I came up with this issue whilst practicing assignment in C. When I try to initialize any variable with it's name(identifier), which doesn't even exist, is not throwing any kind of error.
int x = x;
As far as I know associativity of assignment operator is right to left. So the following code should throw an error whilst i'm initializing a variable with an rvalue which doesn't even exist. Rather, it's assigning some kind of garbage value to it. Why is this happening?
Setting value to be itself is undefined behavior in c standard. After appending compiler option -Winit-self and warning occurs.
GCC 11.2 does diagnose this if you use -Wuninitialized -Winit-self.
I suspect int x = x; may have been used as an idiom1 for “I know what I am doing; do not warn me about x being uninitialized,” and so it was excluded from -Wuninitialized, but a separate warning was provided with -Winit-self.
Note that while the behavior of int x = x; is not defined by the C standard (if it is inside a function and the address of x is not taken), neither does it violate any constraints of the C standard. This means a compiler is not required to diagnose the problem. Choosing to issue a warning message is a matter of choices and quality of the C implementation rather than rules of the C standard.
Apple Clang 11.0 does not warn for int x = x; even with -Wuninitialized -Winit-self. I suspect this is a bug (a deviation from what the authors would have wanted, if not from the rules of the C standard), but perhaps there was some reason for it.
Consider code such as:
int FirstIteration = 1;
int x;
for (int i = 0; i < N; ++i)
{
if (FirstIteration)
x = 4;
x = foo(x);
FirstIteration = 0;
}
A compiler might observe that x = 4; is inside an if, and therefore reason that x might not be initialized in foo(x). The compiler might be designed to issue a warning message in such cases and be unable to reason that the use of FirstIteration guarantees that x is always initialized before being used in foo(x). Taking int x = x; as an assertion from the author that they have deliberately designed the code this way gives them a way to suppress the spurious warning.
Footnote
1 There are several idioms which are used to tell a compiler the author is deliberately using some construction which is often an error. For example, if (x = 3) … is completely defined C code that sets x to 3 and always evaluates as true for the if, but it is usually a mistake as x == 3 was intended. The code if ((x = 3)) … is identical in C semantics, but the presence of the extra parentheses is an idiom used to say “I used assignment deliberately,” and so a compiler may warn for if (x = 3) … but not for if ((x = 3)) ….
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Sequence Points between printf function args; does the sequence point between conversions matter?
(3 answers)
Closed 3 years ago.
Consider code below:
#include <stdio.h>
int main()
{
int x=0,y=5;
printf("x=%d,x_1=%d,sum=%d",x++,x,y+x);
return 0;
}
My assumption on this code was that, x would be printed as 0 and later on postincrement x_1 would be 1 and y+x be 5+1=6
Actual result is x as 0 as expected , x_1 as 1 as expected. But y+x be 5. I am unsure why x retains its previous value though an postincrement had occured. Could you please help clarify this?
I used gcc compiler for the same.
In
printf("x=%d,x_1=%d,sum=%d", x++, x, y+x);
// (a) (b) (b)
you are both updating x (a) and using its value (b) in the same expression (with no intervening sequence point).
That's Undefined Behaviour.
Try
printf("x=%d,x_1=%d,sum=%d", x, x + 1, y + x + 1);
x++;
This is standard undefined behaviour, order of evalution of function arguments is non deterministic. Read [Why are these constructs using pre and post-increment undefined behavior?
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 6 years ago.
testing some code when studying C language,
#include <stdio.h>
#include <math.h>
#define hypotenusa(x, y) sqrt((x) * (x) + (y) * (y))
int main(void) {
int a, x;
x = 2;
a = hypotenusa(++x, ++x);
printf("%d\n", a);
}
And I am getting the answer
6 in one program(dosbox gcc compiler)
7 in codelight gcc compiler and
8 on codeChef online compiler
can anyone explain this behaviour?
my logic says it should be 6 (sqrt(42)) but...
It's undefined behaviour.
After the macro replacement
a = hypotenusa(++x, ++x);
becomes:
a = sqrt((++x) * (++x) + (++x) * (++x));
As you can see x is modified multiple times without any intervening sequence point(s). See What Every C Programmer Should Know About Undefined Behavior.
hypotenusa(++x, ++x) is undefined behavior.
It is up to the compiler which of the parameters gets incremented (and pushed) first - after the macro expansion, there are a total of four instances, and the sequence is not defined.
You should never increment the same variable multiple times in the same statement, to avoid this kind of issues. Using a variable twice in a macro can hide this error and make it really nasty.
The behavior of your macro is undefined, meaning any result is possible.
Chapter and verse
6.5 Expressions
...
2 If a side effect on a scalar object is unsequenced relative to either a different side effect
on the same scalar object or a value computation using the value of the same scalar
object,
the behavior is undefined. If there are multiple allowable orderings of the
subexpressions
of an expression, the behavior is undefined if such an unsequenced side
effect occurs in any
of the orderings.84)
84) This paragraph renders undefined statement expressions such as i = ++i + 1;
a[i++] = i;
while allowing i = i + 1;
a[i] = i;
Basically, if you modify the value of an object more than once in an expression, or both modify an object and use its value in a computation in an expression, the result will not be well-defined unless there is a sequence point in between those operations. With a few exceptions, C does not force left-to-right evaluation of expressions or function parameter evaluations, nor does it mandate that the side effect of ++ or -- be applied immediately after evaluation. Thus, the result of an expression like x++ * x++ will vary from platform to platform, program to program, or even potentially from run to run (although I've never seen that in practice).
For example, given the expression y = x++ * x++, the following evaluation sequence is possible:
t0 <- x // right hand x++, t0 == 2
t1 <- x // left hand x++, t1 == 2
y <- t0 * t1 // y = 2 * 2 == 4
x <- x + 1 // x == 3
x <- x + 1 // x == 4
which doesn't give you the result you expect if you assume left-to-right evaluation.
This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 8 years ago.
Any reason for the following aberration?
Consider the following C program (named PstFixInc.c)
#include <stdio.h>
int main (int argc, char *argv [])
{
int num = 0;
num = (num++) % 4;
printf ("num: %d\n",num);
return 0;
}
If compiled with gcc 4.8.1:
gcc -o PstFix.exe PstFixInc.c
and then executed, you get the result:
num: 0
If compiled with Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86
cl PstFixInc.c
and then executed, you get the result:
num: 1
What you have is undefined behavior, you are modifying num and using its previous value other than to determine the value to be stored within the same sequence point. This is covered in the draft C99 standard section 6.5 paragraph 2 which says:
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an
expression.72) Furthermore, the prior value shall be read only to
determine the value to be stored.73)
There are also two examples of undefined behavior:
i = ++i + 1;
a[i++] = i;
The first one is pretty similar to your example.
Using clang even gives you a nice warning:
warning: multiple unsequenced modifications to 'num' [-Wunsequenced]
num = (num++) % 4;
~ ^
This is undefined behavior.
You're assigning to the same variable twice without an interleaving sequence point.
This line:
num = (num++) % 4;
is undefined behavior per the C standard. Any result that the code produces is "correct".
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 10 years ago.
Cannot explain the output of the following program. According to my knowledge the output should be 19, but running it gives me output of 20. I used gcc to compile this program.
int main()
{
int x, y = 5;
x = ++y + ++y + --y;
printf("%d", x);
return 0;
}
Your program exploits undefined behavior as you modify y multiple times between two sequence points (in your case, the end of the statement). If you turn on warnings with -Wall, your compiler is probably even going to warn you about that.
6+7+6 = 19
so 19 will be your output