Can someone explain how this C snippet will be evaluated w.r.t sequence points?
Asked Answered
R

1

5

Is this Undefined Behavior under C? I say this because I think that the function inc(int *k) can be thought of as an expression whose side effect is to update the value at the address of k. So, would that make it equivalent to i=i++, which is UB?

#include <stdio.h>
/*Edited(See comments below on dbush's answer)*/
int inc(int *k) {return ++(*k);}
/*End of edit*/
int main() 
{
  int i=0;
  int *ptr = &i;
  i = inc(ptr);
  printf("%d\n", i);
}
Rarefied answered 23/8, 2018 at 1:54 Comment(0)
Q
7

The behavior is well defined because calling a function counts as a sequence point, and each statement within the function is also a sequence point. It is not the same as if the body of the function were put in its place.

First inc is called. This invokes a sequence point.

Within the function, the statement return ++(*k) is executed, which first evaluates the containing expression. This results in i in main getting incremented to 1, and the expression evaluates to the new value of i, which is 1. The return statement returns that value from the function, and the completion of that statement is another sequence point, so the side effect of incrementing i is guaranteed to be complete.

Back in main, the value of 1 returned from inc is then assigned to i.

Had you instead done this:

i = ++(*ptr);

That would be undefined behavior because there is no sequence point between assigning to i and the side effect of incrementing i via *ptr.

Quar answered 23/8, 2018 at 2:18 Comment(10)
The sequence point for calling the function is before the evaluation of the function body and does not sequence expressions in the function relative to the assignment side effect. C 2018 6.5.2.2 10: “There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.”Coniology
However, that makes the side effects indeterminately sequenced rather than unsequenced, and indeterminate sequencing of side effects on a scalar object does not trigger the rule for undefined behavior, unlike unsequenced effects. And the assignment side effect is, by the semantics of assignment, sequenced after the value computation of the right side, which means the expressions in the function must precede the assignment, which means the sequence point at the end of the full expression in the function precedes the assignment, and the increment precedes that sequence point.Coniology
@EricPostpischil: There's also a sequence point when the function returns: the return statement has a sequence point at the end of it.Lemuel
@JonathanLeffler: C 2018 6.8.6.4, which discusses return statements does not say there is a sequence point. 7.1.4 3 says there is a sequence point before standard library functions return, but that does not apply to non-library functions.Coniology
@EricPostpischil: But there is a complete expression after the return and the end of that marks a sequence point, just as much as if there was an explicit statement about it.Lemuel
@JonathanLeffler: That sequence point is already mentioned in my earlier comments: “the sequence point at the end of the full expression in the function.”Coniology
Hi, I realize that I made a mistake in my inc function. I wanted to have a function which increments the value at the address. I am adding an edit. I think that the statement " calling a function counts as a sequence point" still explains that. I am still a little bit confused though. Can a function evaluation be thought of as an expression and if so, am I right in assuming that the side-effect is updating the pointer value in this example? If this is a correct, I interpret your statement to mean that the location pointed to is guaranteed to be updated when the function returns.Rarefied
@abjoshi I figured as much regarding the increment. I updated the answer to reflect the modified question. As for the function evaluation, the actual function call is a sequence point, although if an expression contains multiple function calls then the order in which they are called is not specified. There is however a sequence point after every statement in a function, so the side effect of the increment is guaranteed to be complete by the time the function returns.Quar
@Quar , based on what you said, the value of d here is undefined? i = d=inc(ptr) + inc(ptr); printf("%d, %d\n", d, d++);Rarefied
@abjoshi The d=inc(ptr) + inc(ptr) part is not undefined but unspecified, since you don't know which inc gets called first but there are still sequence points between reads and writes. On the other hand printf("%d, %d\n", d, d++); is undefined behavior because d is read and written without a sequence point.Quar

© 2022 - 2024 — McMap. All rights reserved.