Knowing your sequence points

A

akarl

Hi all,

Why do I get a warning from gcc with the following program?

[test]$ cat test.c
#include <stdio.h>

int f(int n)
{
return n;
}


int main(void)
{
int n = 0;

printf("%i\n", f(n++) + n);
return 0;
}

[test]$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:13: warning: operation on ‘n’ may be undefined

One of the sequence point cases is defined as: "The point of calling a
function, after evaluating its arguments." If I got it right, that rule
can be applied to `f(n++)' which is evaluated before `n' since addition
is left associative. I can't see the ambiguity here.


August

(I would never write this kind of code in practice, but it's good to
know how the standard is defined.)
 
P

pete

akarl said:
Hi all,

Why do I get a warning from gcc with the following program?

[test]$ cat test.c
#include <stdio.h>

int f(int n)
{
return n;
}

int main(void)
{
int n = 0;

printf("%i\n", f(n++) + n);
return 0;
}

[test]$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:13: warning: operation on ‘n’ may be undefined

One of the sequence point cases is defined as: "The point of calling a
function, after evaluating its arguments."
If I got it right, that rule
can be applied to `f(n++)' which is evaluated before
`n' since addition is left associative.
I can't see the ambiguity here.

That's not what left associative means.
 
A

akarl

pete said:
akarl said:
Hi all,

Why do I get a warning from gcc with the following program?

[test]$ cat test.c
#include <stdio.h>

int f(int n)
{
return n;
}

int main(void)
{
int n = 0;

printf("%i\n", f(n++) + n);
return 0;
}

[test]$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:13: warning: operation on ‘n’ may be undefined

One of the sequence point cases is defined as: "The point of calling a
function, after evaluating its arguments."
If I got it right, that rule
can be applied to `f(n++)' which is evaluated before
`n' since addition is left associative.
I can't see the ambiguity here.


That's not what left associative means.

Yes, of course (only one addition operation). How stupid of me. So the
ambiguity here is that the *evaluation order* of the operands of `+' is
unspecified, right?

August
 
J

Jack Klein

Hi all,

Why do I get a warning from gcc with the following program?

[test]$ cat test.c
#include <stdio.h>

int f(int n)
{
return n;
}


int main(void)
{
int n = 0;

printf("%i\n", f(n++) + n);
return 0;
}

[test]$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:13: warning: operation on ‘n’ may be undefined

Yes, the operation on 'n' may be undefined. The standard says:

"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be read only to determine the value
to be stored."

The printf() call in your call does not modify the value of 'n' more
than once. The expression 'n++' modifies 'n' exactly once, and uses
the original value of 'n' only for the purpose of computing the new
value. But the '+ n' subexpression attempts to access the prior value
of 'n' in a way that is not used in the computation of the new value.
One of the sequence point cases is defined as: "The point of calling a
function, after evaluating its arguments." If I got it right, that rule
can be applied to `f(n++)' which is evaluated before `n' since addition
is left associative. I can't see the ambiguity here.

No, you are wrong, associatively has nothing at all to do with order
of evaluation. Only sequence points impose an order of evaluation.
August

(I would never write this kind of code in practice, but it's good to
know how the standard is defined.)

Let's take an example that doesn't have undefined behavior:

#include <stdio.h>

int f1(void)
{
puts("function 1\n");
return 1;
}

int f2(void)
{
puts("function 1\n");
return 2;
}

int main(void)
{
printf("the sum is %d\n", f1() + f2());
return 0;
}

This function does not define or contain any objects at all, so the
paragraph I quoted from the standard certainly does not apply.

Because the order of evaluation between sequence points is
unspecified, the output could be either of the following two
sequences, and must be one of the two:

function 1
function 2
the sum is 3

....or:

function 2
function 1
the sum is 3

In fact, it may change between one and the other if you change the
settings you use to invoke your compiler, for example enable or
disable optimization.

If just so happens that if your compiler evaluates the subexpression
'f(n++)' first, the result is defined because there is a sequence
point imposed by calling the function before the '+ n' subexpression
reads the value of 'n' again.

But if your compiler evaluates 'n' in the '+ n' subexpression before
evaluating the 'f(n++)' subexpression, there is no sequence point
between the unrelated read and the modification, the behavior is
undefined.

Finally, since the order of evaluation is something the standard
states is unspecified, it means that the compiler does not have to
tell you which order it uses, and is free to change it based on
settings, the day of the week, or the phase of the moon.

Since one of the unspecified paths generates undefined behavior, the
whole thing should be treated as undefined.
 
P

pete

akarl said:
Yes, of course (only one addition operation). How stupid of me. So the
ambiguity here is that the *evaluation order*
of the operands of `+' is unspecified, right?

Yes. There are rules that say that modifying n
and reading n between sequence points, is undefined,
even though it might seem to be only unspecified.

I think it's good to avoid side effects in function arguments.
I absentmindedly used an argument with side effects in the
Re: A question on string literals
thread, thereby confusing Default User.
It would have been more better if I had
incremented the pointer prior to the function call
instead of in the function call.
 
M

Martin Ambuhl

akarl said:
Hi all,

Why do I get a warning from gcc with the following program? [...]
printf("%i\n", f(n++) + n); [...]
test.c:13: warning: operation on ‘n’ may be undefined

Because the the value of 'f(n++) + n' is undefined.
One of the sequence point cases is defined as: "The point of calling
a function, after evaluating its arguments." If I got it right, that
rule can be applied to `f(n++)' which is evaluated before `n' since
addition is left associative. I can't see the ambiguity here.

The order of evaluation of the operands f(n++) and n is not defined.
Associativity (which isn't a C concept, anyway) doesn't enter into it.
 
S

Suman

Jack said:
Hi all,

Why do I get a warning from gcc with the following program?

[test]$ cat test.c
#include <stdio.h>

int f(int n)
{
return n;
}


int main(void)
{
int n = 0;

printf("%i\n", f(n++) + n);
return 0;
}

[test]$ gcc -Wall test.c
test.c: In function 'main':
test.c:13: warning: operation on 'n' may be undefined

Yes, the operation on 'n' may be undefined. The standard says:

"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be read only to determine the value
to be stored."

The printf() call in your call does not modify the value of 'n' more
than once. The expression 'n++' modifies 'n' exactly once, and uses
the original value of 'n' only for the purpose of computing the new
value. But the '+ n' subexpression attempts to access the prior value
of 'n' in a way that is not used in the computation of the new value.
One of the sequence point cases is defined as: "The point of calling a
function, after evaluating its arguments." If I got it right, that rule
can be applied to `f(n++)' which is evaluated before `n' since addition
is left associative. I can't see the ambiguity here.

No, you are wrong, associatively has nothing at all to do with order
of evaluation. Only sequence points impose an order of evaluation.
August

(I would never write this kind of code in practice, but it's good to
know how the standard is defined.)

Let's take an example that doesn't have undefined behavior:

#include <stdio.h>

int f1(void)
{
puts("function 1\n");
return 1;
}

int f2(void)
{
puts("function 1\n");
return 2;
}

int main(void)
{
printf("the sum is %d\n", f1() + f2());
return 0;
}

This function does not define or contain any objects at all, so the
paragraph I quoted from the standard certainly does not apply.

Because the order of evaluation between sequence points is
unspecified, the output could be either of the following two
sequences, and must be one of the two:

function 1
function 2
the sum is 3

...or:

function 2
function 1
the sum is 3

<nitpick>
or more likely:
function 1
function 1
the sum is 3
 
J

Jack Klein

Jack Klein wrote:

[snip]
<nitpick>
or more likely:
function 1
function 1
the sum is 3
</nitpick>

Kind of takes the away the whole point of the example, doesn't it?
Makes it really, really indeterminate!

Thanks, Suman, nice catch.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top