Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sequence points when calling functions in C and undefined/unspecified behaviour

I'm trying to pin down my understanding of sequence points in C -- just wanted to check something. At present, I believe that (1) is undefined whereas (2) is merely unspecified, on the basis that in (2), there are sequence points after evaluating the arguments for g and h (so we're not modifying i twice between sequence points), but the order of evaluation of the arguments of f is still unspecified. Is my understanding correct?

#include <stdio.h>

int g(int i) {
    return i;
}

int h(int i) {
    return i;
}

void f(int x, int y) {
    printf("%i", x + y);
}

int main() {
    int i = 23;
    f(++i, ++i); // (1)
    f(g(++i), h(++i)); // (2)
    return 0;
}

EDIT:

It seems the key point here is whether the compiler is free to perform both the increments before either g or h is called -- my understanding from the answers below is that it is, although I'd appreciate confirmation that that's the case.

like image 605
Stuart Golodetz Avatar asked Dec 09 '22 23:12

Stuart Golodetz


2 Answers

Incorrect. Sequence points specify a partial order on the allowed ordering of operations. In case (2), there are sequence points:

  1. At the semicolon at the end of the line (1)
  2. After the evaluation of the arguments of g (i.e. the ++i) but before the call to g
  3. After the evaluation of the arguments of h (i.e. the ++i) but before the call to h
  4. After the evaluation of the arguments of f (i.e. after f and g have returned) but before the call to f
  5. After the return from f

So the partial order looks like this, from top to bottom:

    1
   / \
  /   \
 2     3
  \   /
   \ /
    4
    |
    | 
    5

2 and 3 are not ordered with respect to each other, since the order of evaluation of arguments is unspecified. Since i gets modified twice between the sequence points 1 and 4, the behavior is undefined.

like image 142
Adam Rosenfield Avatar answered Dec 31 '22 02:12

Adam Rosenfield


No, per 6.5.2.2 10 there is no sequence point between the evaluation of subexpression arguments, just before the actual call.

One way of looking at it is that it is unspecified whether the behaviour is undefined; if the implementation sequences the two ++i subexpressions before any call to g or h then the behaviour is undefined, but if the ++i subexpressions are evaluated as late as possible (immediately before calling g and h respectively) then the behaviour is unspecified. However, because the implementation is always at liberty to choose between any allowed unspecified behaviour then the overall result is undefined.

like image 39
ecatmur Avatar answered Dec 31 '22 02:12

ecatmur