Arjun Suresh (talk | contribs) (→Precedence Rule Violated? No) |
|||
(42 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | <syntaxhighlight lang="c"> | + | <metadesc>Undefined value in C language, sequence point</metadesc> |
+ | <syntaxhighlight lang="c" name="undefined_value" > | ||
#include<stdio.h> | #include<stdio.h> | ||
int main() | int main() | ||
{ | { | ||
int x=10, y; | int x=10, y; | ||
− | y = x++ + ++x; | + | y = (x++) + (++x); |
printf("%d %d %d %d ", y, x++, x, ++x); | printf("%d %d %d %d ", y, x++, x, ++x); | ||
} | } | ||
Line 17: | Line 18: | ||
'''d)''' 22 13 13 13 | '''d)''' 22 13 13 13 | ||
+ | ==={{Template:Author|Arjun Suresh|{{arjunweb}} }}=== | ||
None of the choices are correct as per [http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf C standard]. This is because the statement | None of the choices are correct as per [http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf C standard]. This is because the statement | ||
− | y = x++ + ++x; | + | y = (x++) + (++x); |
can causes undefined behavior, so does the statement | can causes undefined behavior, so does the statement | ||
printf("%d %d %d %d ", y, x++, x, ++x); | printf("%d %d %d %d ", y, x++, x, ++x); | ||
− | C standard says that the side effects of an operation | + | C standard says that the side effects of an operation (for ++a; modification of a is a side-effect and return of a+1 is main effect) need to be completed only before the next [https://en.wikipedia.org/wiki/Sequence_point sequence point]. This relaxation is given so that the compiler would be able to generate the most optimal code (which run faster). But as a consequence, programmer shouldn't do a read and a write from a memory location between two consecutive sequence points or otherwise the result would be undefined. |
In the statement, | In the statement, | ||
− | y = x++ + ++x; | + | y = (x++) + (++x); |
− | There are 2 reads to the memory location of x and 2 writes to the same | + | There are 2 reads to the memory location of x and 2 writes to the same between two consecutive sequence points. So, the result of this statement has no guarantee as per C standard. |
Similarly, the statement | Similarly, the statement | ||
printf("%d %d %d %d ", y, x++, x, ++x); | printf("%d %d %d %d ", y, x++, x, ++x); | ||
− | is undefined. In a function call in C, | + | is undefined. In a function call in C, the order in which the argument expressions are processed is not defined. The only thing defined is that all arguments must be processed before the next sequence point- which here is the start of execution of the called function. |
− | + | Undefined value means compiler can give any value. i.e.; different compilers or even different versions of the same compiler can give different answers. As per C standard, no programmer should write this code. This is different from compiler defined, in which case the output is clearly defined by the compiler and programmer can write those code as long as he is aware of the compiler. Example of compiler defined code is sizeof(int). | |
+ | ==Still undefined== | ||
+ | <syntaxhighlight lang="c" name="undefined" > | ||
+ | #include<stdio.h> | ||
+ | int main() | ||
+ | { | ||
+ | int x=10; | ||
+ | printf("%d %d %d\n", x++, x, ++x); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | asuresh@parambara:~$ gcc undefined.c | ||
+ | asuresh@parambara:~$ ./a.out | ||
+ | 11 12 12 | ||
+ | asuresh@parambara:~$ icc undefined.c | ||
+ | asuresh@parambara:~$ ./a.out | ||
+ | 10 12 12 | ||
+ | asuresh@parambara:~$ clang undefined.c | ||
+ | asuresh@parambara:~$ ./a.out | ||
+ | 10 11 12 | ||
+ | |||
+ | ==Is this Problem with ++? NO == | ||
+ | <syntaxhighlight lang="c" name="undefined" > | ||
+ | #include<stdio.h> | ||
+ | int main() | ||
+ | { | ||
+ | int x=10; | ||
+ | printf("%d %d %d\n", x=1, x, x=2); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | asuresh@parambara:~$ gcc -Wall undefined.c | ||
+ | undefined.c: In function ‘main’: | ||
+ | undefined.c:6:35: warning: operation on ‘x’ may be undefined [-Wsequence-point] | ||
+ | printf("%d %d %d\n", x=1, x, x=2); | ||
+ | ^ | ||
+ | undefined.c:6:35: warning: operation on ‘x’ may be undefined [-Wsequence-point] | ||
+ | asuresh@parambara:~$ ./a.out | ||
+ | 1 1 1 | ||
+ | asuresh@parambara:~$ icc -Wall undefined.c | ||
+ | asuresh@parambara:~$ ./a.out | ||
+ | 1 2 2 | ||
+ | asuresh@parambara:~$ clang -Wall undefined.c | ||
+ | asuresh@parambara:~$ ./a.out | ||
+ | 1 1 2 | ||
+ | |||
+ | |||
+ | ==Precedence Rule Violated? No== | ||
+ | Undefined behaviour is happening not because C is violating precedence rule. Precedence (and associativity which is used when precedence of operators are same) rule is used to specify the operands for operations. But the actual execution order might be different. For example: | ||
+ | x = a*b+c*d; | ||
+ | |||
+ | After applying precedence rule, we get | ||
+ | x = ((a*b) + (c*d)); | ||
+ | |||
+ | Thus the first $*$ has operands $a$ and $b$, the second $*$ has operands $c$ and $d$, the $+$ has operands returned by the result of two $*$ and $=$ has left operand $x$ and right operand the result of $+$. But, during execution $(a*b)$ or $(c*d)$ can occur first as both these won't be violating the precedence rule. | ||
+ | |||
+ | Similarly, if we take | ||
+ | y = x++ * ++x; | ||
+ | After applying precedence rule, we get | ||
+ | y = ((x++) * (++x)); | ||
+ | $x$++ or ++$x$ can happen first. Suppose ++$x$ happened first. It'll surely return $x+1$. But whether this incremented $x$ is used by $x$++ is not guaranteed. This increment can happen to $x$ ANYTIME before the next sequence point, which here is the ; at the end of the expression. This makes this code produce undefined behaviour. | ||
− | + | ==Other Examples for Undefined behaviour== | |
+ | int i = 2; | ||
+ | i = i++; | ||
+ | printf("%d\n", i); | ||
+ | Possible outputs: {3, 2} | ||
+ | int i = 2; | ||
+ | a[i] = i++; | ||
+ | Possible Results: a[2] = 2, a[3] = 2 | ||
− | + | int i = 2, j; | |
+ | j = (i++) * (++i); | ||
+ | printf("%d", j); | ||
+ | Possible outputs: {6, 9} | ||
+ | |||
+ | int i = 2; | ||
+ | printf("%d %d", i, i++); | ||
+ | Possible outputs: {(2,3), (2,2)} | ||
+ | {{Template:FBD}} | ||
− | |||
− | [[Category: | + | [[Category:Coding Questions]] |
− |
<syntaxhighlight lang="c" name="undefined_value" >
int main() {
int x=10, y; y = (x++) + (++x); printf("%d %d %d %d ", y, x++, x, ++x);
} </syntaxhighlight>
a) 22,10,11,13
b) 22,11,11,11
c) 12,10,11,13
d) 22 13 13 13
None of the choices are correct as per C standard. This is because the statement
y = (x++) + (++x);
can causes undefined behavior, so does the statement
printf("%d %d %d %d ", y, x++, x, ++x);
C standard says that the side effects of an operation (for ++a; modification of a is a side-effect and return of a+1 is main effect) need to be completed only before the next sequence point. This relaxation is given so that the compiler would be able to generate the most optimal code (which run faster). But as a consequence, programmer shouldn't do a read and a write from a memory location between two consecutive sequence points or otherwise the result would be undefined.
In the statement,
y = (x++) + (++x);
There are 2 reads to the memory location of x and 2 writes to the same between two consecutive sequence points. So, the result of this statement has no guarantee as per C standard.
Similarly, the statement
printf("%d %d %d %d ", y, x++, x, ++x);
is undefined. In a function call in C, the order in which the argument expressions are processed is not defined. The only thing defined is that all arguments must be processed before the next sequence point- which here is the start of execution of the called function.
Undefined value means compiler can give any value. i.e.; different compilers or even different versions of the same compiler can give different answers. As per C standard, no programmer should write this code. This is different from compiler defined, in which case the output is clearly defined by the compiler and programmer can write those code as long as he is aware of the compiler. Example of compiler defined code is sizeof(int).
<syntaxhighlight lang="c" name="undefined" >
#include<stdio.h>
int main() {
int x=10; printf("%d %d %d\n", x++, x, ++x);
} </syntaxhighlight>
asuresh@parambara:~$ gcc undefined.c asuresh@parambara:~$ ./a.out 11 12 12 asuresh@parambara:~$ icc undefined.c asuresh@parambara:~$ ./a.out 10 12 12 asuresh@parambara:~$ clang undefined.c asuresh@parambara:~$ ./a.out 10 11 12
<syntaxhighlight lang="c" name="undefined" >
#include<stdio.h>
int main() {
int x=10; printf("%d %d %d\n", x=1, x, x=2);
} </syntaxhighlight>
asuresh@parambara:~$ gcc -Wall undefined.c undefined.c: In function ‘main’: undefined.c:6:35: warning: operation on ‘x’ may be undefined [-Wsequence-point] printf("%d %d %d\n", x=1, x, x=2); ^ undefined.c:6:35: warning: operation on ‘x’ may be undefined [-Wsequence-point] asuresh@parambara:~$ ./a.out 1 1 1 asuresh@parambara:~$ icc -Wall undefined.c asuresh@parambara:~$ ./a.out 1 2 2 asuresh@parambara:~$ clang -Wall undefined.c asuresh@parambara:~$ ./a.out 1 1 2
Undefined behaviour is happening not because C is violating precedence rule. Precedence (and associativity which is used when precedence of operators are same) rule is used to specify the operands for operations. But the actual execution order might be different. For example:
x = a*b+c*d;
After applying precedence rule, we get
x = ((a*b) + (c*d));
Thus the first $*$ has operands $a$ and $b$, the second $*$ has operands $c$ and $d$, the $+$ has operands returned by the result of two $*$ and $=$ has left operand $x$ and right operand the result of $+$. But, during execution $(a*b)$ or $(c*d)$ can occur first as both these won't be violating the precedence rule.
Similarly, if we take
y = x++ * ++x;
After applying precedence rule, we get
y = ((x++) * (++x));
$x$++ or ++$x$ can happen first. Suppose ++$x$ happened first. It'll surely return $x+1$. But whether this incremented $x$ is used by $x$++ is not guaranteed. This increment can happen to $x$ ANYTIME before the next sequence point, which here is the ; at the end of the expression. This makes this code produce undefined behaviour.
int i = 2; i = i++; printf("%d\n", i); Possible outputs: {3, 2}
int i = 2; a[i] = i++; Possible Results: a[2] = 2, a[3] = 2
int i = 2, j; j = (i++) * (++i); printf("%d", j); Possible outputs: {6, 9}
int i = 2; printf("%d %d", i, i++); Possible outputs: {(2,3), (2,2)}
<syntaxhighlight lang="c">
int main() {
int x=10, y; y = x++ + ++x; printf("%d %d %d %d ", y, x++, x, ++x);
} </syntaxhighlight>
a) 22,10,11,13
b) 22,11,11,11
c) 12,10,11,13
d) 22 13 13 13
None of the choices are correct as per C standard. This is because the statement
y = x++ + ++x;
can causes undefined behavior, so does the statement
printf("%d %d %d %d ", y, x++, x, ++x);
C standard says that the side effects of an operation should be complete only before the next sequence point. This relaxation is given so that the compiler would be able to generate the most optimal code (which run faster). But as a consequence, programmer shouldn't do a read and a write from a memory location within a sequence point or otherwise the result would be undefined.
In the statement,
y = x++ + ++x;
There are 2 reads to the memory location of x and 2 writes to the same within a sequence point. So, the result of this statement has no guarantee as per C standard.
Similarly, the statement
printf("%d %d %d %d ", y, x++, x, ++x);
is undefined. In a function call in C, the arguments are pushed onto the stack from right to left (the left most argument would be on top of the stack, so that variable no. of arguments can work in C). But the order in which the argument expressions are processed is not defined. The only thing defined is that all arguments must be processes before the next sequence point- which here is the execution of the called function.
I have seen many people saying C is so stupid because of these undefined behaviors. But that's the power of C. A programmer in C should know about these behaviors and avoid writing undefined codes.