Keith said:
Shao Miller said:
Martin O'Brien wrote:
int a = 1;
printf("%d", ++a, a + 5);
[...]
The difference would be treating each of the arguments as its own
expression. In that example, each of the operators is either unary or
binary, so the whole expression is a tree with at most two branches at
any branching. With a function call, the arguments can be N branches at
the branch-point, and they are all grouped together for theoretically
simultaneous evaluation.
A argument of mine went: Each sub-expression for each argument is where
the constraints regarding reading previous values is. If you discard
that and say the the constraint is on the whole expression, well-defined
behaviour softly and suddenly vanishes away.
I think part of the problem is that you're thinking in terms
of expressions. The relevant concept in sequence points,
not expressions.
Well, not exactly. It should be clear that the sequence points were
never disputed as being critical to the discussion. One bit that's
critical is to observe that:
Between sequence points, evaluation yields side effects whose order is
not only unspecified, but whose order is not even guaranteed to be
chronologically distinct.
We have to put one foot in front of the other and then repeat for the
other foot in order to walk. We cannot put both feet forward at the
same time without constituting a hop. Side effects can be akin to
hopping or walking, according to some of this thread's discussion.
Without this, the order discussed in 6.5.2.2p10 would proceed one side
effect at a time and the discarded result of 'a + 5' would make no
difference.
There can be multiple expressions between two
consecutive sequence points (if, as above, they're subexpressions
of a larger expression), and there can be multiple sequence points
within an expression (some operators such as && and || impose
sequence points). It's sequence points, not expressions, that
govern when side effects can take place.
Right. What still sits uneasy with me is the implications for/of
'volatile'. 'n1256.pdf' has 6.7.3p6, which details a requirement for
strict evaluation according the semantics. I have always taken this to
mean that the semantics define the last line of:
volatile int i;
i = 1;
i = i + i;
to read the value of 'i' twice. Once when left 'i' for addition turns
into a value and again when the right 'i' turns into a value. The order
doesn't matter. To me, that suggests that each step of evaluation is a
distinct moment in time, by the abstract semantics.
Then 5.1.2.3p8 details the possibility of "a one-to-one correspondence
between abstract and actual semantics" and an apparent redundancy for
'volatile' in such an instance. So I get the impression that we can
"hop" if and only if we would land in the same spot that "walking" would
take us.
So it seemed quite natural that there could be no license to schedule
the write to 'a' in the second argument and the read of 'a' in the third
for the same time if there was a chance of interfering with results
being identical to the abstract semantics.
printf("%d", ++a, a + 5);
But accepting that 6.5p2 applies to the whole expression, and not just
to each of the comma-separated list of argument expressions, would take
precedence and declare undefined behaviour before we can debate the
license to schedule pieces of evaluation with simultaneous order.
My treatment was more along the lines of:
static int a = 1;
struct foo {
int arg2;
int arg3;
};
static int func(struct foo params) {
return params.arg2;
}
int main(void) {
struct foo
bar = { .arg2 = ++a, .arg3 = a + 5 },
baz = { .arg2 = func(bar) };
return 0;
}
where 6.7.8p23 is very similar to 6.5.2.2p10; unspecified evaluation
order, but perhaps the 'arg3' member will never be used. So my
treatment of the arguments to 'printf' was that we temporarily left the
realm of "expressiondom" and 6.5p2 did not apply to the whole, much as
the initializers are separated, above.
I suppose it just seems counter-intuitive to me that function arguments
be treated the same as sub-expressions for the computation of a single
value, instead of as independent expressions not part of a larger
expression. I know that the evaluation of the call is going to yield a
value, but that's certainly _after_ a sequence point, so the sudden
interdependence of the arguments doesn't sit right.
But regardless of that, thanks again.