Does the statement `int val = (++i > ++j) ? ++i : ++j;` invoke undefined behavior?

The behavior of this code is well defined.

The first expression in a conditional is guaranteed to be evaluated before either the second expression or the third expression, and only one of the second or third will be evaluated. This is described in section 6.5.15p4 of the C standard:

The first operand is evaluated; there is a sequence point between its evaluation and the evaluation of the second or third operand (whichever is evaluated). The second operand is evaluated only if the first compares unequal to 0; the third operand is evaluated only if the first compares equal to 0; the result is the value of the second or third operand (whichever is evaluated), converted to the type described below.

In the case of your expression:

int val = (++i > ++j) ? ++i : ++j;

++i > ++j is evaluated first. The incremented values of i and j are used in the comparison, so it becomes 2 > 3. The result is false, so then ++j is evaluated and ++i is not. So the (again) incremented value of j (i.e. 4) is then assigned to val.

too late, but maybe useful.

(++i > ++j) ? ++i : ++j;

In the document ISO/IEC 9899:201xAnnex C(informative)Sequence points we find that there is a sequence point

Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated

In order to be well defined behavior one must not modify 2 times (via side-effects) the same object between 2 sequence points.

In your expression the only conflict that could appear would be between the first and second ++i or ++j.

At every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine (this is what you would compute on paper, like on a turing machine).

Quote from Program execution

The presence of a sequence point between the evaluation of expressions A and B implies that every value computation and side effect associated with A is sequenced before every value computation and side effect associated with B.

When you have side-effects in your code, they are sequenced by different expressions. The rule says that between 2 sequence points you can permute these expressions as you wish.

For example. i = i++. Because none of the operators involved in this expression represent sequence points, you can permute the expressions that are side-effects as you want. The C language allows you to use any of these sequences

i = i; i = i+1; or i = i+1; i=i; or tmp=i; i = i+1 ; i = tmp; or tmp=i; i = tmp; i = i+1; or anything that provides the same result as the abstract semantics of computation asks for interpretation of this computation. The Standard ISO9899 defines the C language as abstract semantics.

There may be no UB in your program, but in the question: Does the statement int val = (++i > ++j) ? ++i : ++j; invoke undefined behavior?

The answer is yes. Either or both of the increment operations may overflow, since i and j are signed, in which case all bets are off.

Of course this doesn't happen in your full example because you've specified the values as small integers.