Why does (*p=*p) & (*q=*q);
in C trigger undefined behavior if p
and q
are equal.
int f2(int * p, int * q)
{
(*p=*p) & (*q=*q);
*p = 1;
*q = 2;
return *p + *q;
}
Source (Nice article by the way): http://blog.frama-c.com/index.php?post/2012/07/25/On-the-redundancy-of-C99-s-restrict
p is the value of p while *p is the value stored in the memory location pointed by p . When you want to indirectly access the value of an integer i , you can have an integer pointer point to it ( int *p = &i ) and use that pointer to modify the value of i indirectly ( *p = 10 ).
In C programming language, *p represents the value stored in a pointer. ++ is increment operator used in prefix and postfix expressions. * is dereference operator.
The expression *p++ is treated as *(p++) as the precedence of postfix ++ is higher than *. Therefore the output of second program is “arr[0] = 10, arr[1] = 20, *p = 20 “. The expression *++p has two operators of same precedence, so compiler looks for associativity. Associativity of operators is right to left.
If p is a pointer (effectively a memory address), then *p is the data that it is pointing to. The & as an operator is the "address of" operator. If p is a bit of data, then &p is a pointer pointing to the data.
The ruling of the C11 Standard on the statement
(*p=*p) & (*q=*q);
is:
§6.5p3
The grouping of operators and operands is indicated by the syntax. 85) Except as specified later, side effects and value computations of subexpressions are unsequenced.
Since §6.5.10 Bitwise AND operator fails to mention sequencing of its operands, it follows that (*p=*p)
and (*q=*q)
are unsequenced.
§6.5p2
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)
Both assignments (*p=*p)
and (*q=*q)
are unsequenced w.r.t. each other by §6.5p3, and have a side-effect on the same object if p==q
. Therefore, if p==q
, then by §6.5p2 we have UB.
§3.4.3
undefined behaviour
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements.
By this clause we know that the standard imposes no requirements on UB. This is commonly interpreted by compilers as a license to ignore the possibility that such behaviour occurs.
In particular, it allows the compiler to not handle the case p == q
, which means that it may assume that p != q
.
Because (*p=*p)
and (*q=*q)
may be assumed by the combined premises P1, P2 and P3 not to invoke UB, they may also be assumed to be loads and stores to different memory locations. This also means that the return value of f2
must be 3
and not 4
. If p == q
, the Standard imposes no requirements on what occurs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With