Sequence point(s)

N

Neelesh Bodas

Hello,

Consider this piece of code:
int swap(int &x, int &y)
{
y = (x-y) + (x=y);
}

This code "claims" to swap values of x and y. I gather that this
claims holds true only if (x-y) gets evaluated before (x==y). Since
there is no sequence point at (+), hence I assume that the order of
evaluation of operands of (+) is unspecified and hence the claim's
isn't always true. Is that correct? Or is there a sequence point at
(x=y) which forces the evaluation of (x-y) before it, there by making
the claim always true?
 
B

Bo Persson

Neelesh said:
Hello,

Consider this piece of code:
int swap(int &x, int &y)
{
y = (x-y) + (x=y);
}

This code "claims" to swap values of x and y. I gather that this
claims holds true only if (x-y) gets evaluated before (x=y). Since
there is no sequence point at (+), hence I assume that the order of
evaluation of operands of (+) is unspecified and hence the claim's
isn't always true. Is that correct? Or is there a sequence point at
(x=y) which forces the evaluation of (x-y) before it, there by
making the claim always true?

No, it doesn't work. Even if there were sequence points, like for user
defined operators for a class type, the order of evaluation is still
not defined. Obviously, (x-y) and (x=y) must both be evaluated before
the +, but we we don't know their relative order.

Might work for Java. :)


Bo Persson
 
J

Juha Nieminen

Bo Persson said:
Obviously, (x-y) and (x=y) must both be evaluated before
the +, but we we don't know their relative order.

Btw, I wonder if the compiler is allowed to skip evaluating
subexpressions if it knows that the result will not affect anything.
For example if you have something like:

int value = expression1 * expression2;

and expression1 evaluates to 0, then expression2 will have no effect on
the result. Is the compiler allowed to skip evaluating expression2 in
that case?
 
J

Johannes Schaub (litb)

Neelesh said:
Hello,

Consider this piece of code:
int swap(int &x, int &y)
{
y = (x-y) + (x=y);
}

This code "claims" to swap values of x and y. I gather that this
claims holds true only if (x-y) gets evaluated before (x==y). Since
there is no sequence point at (+), hence I assume that the order of
evaluation of operands of (+) is unspecified and hence the claim's
isn't always true. Is that correct? Or is there a sequence point at
(x=y) which forces the evaluation of (x-y) before it, there by making
the claim always true?

it, while the former read is not
for determining the value to store. Thus you have behavior undefined. This
also applies to C++0x, which allows more things with defined behavior

++i = 0; // defined by c++0x, undefined by C++03
++ ++i; // defined by c++0x, undefined by C++03
i = ++i; // defined by c++0x, undefined by C++03
i = i++; // undefined by both C++0x and C++0x
 
B

Bo Persson

Juha said:
Btw, I wonder if the compiler is allowed to skip evaluating
subexpressions if it knows that the result will not affect anything.
For example if you have something like:

int value = expression1 * expression2;

and expression1 evaluates to 0, then expression2 will have no
effect on the result. Is the compiler allowed to skip evaluating
expression2 in that case?

If expression2 has no side effects, we cannot tell and the compiler
can do whatever it likes.

However for something like

int value = 0 * print(x);

the value of x have better be printed.


Bo Persson
 
T

thomas

Hello,

Consider this piece of code:
int swap(int &x, int &y)
{
        y = (x-y) + (x=y);

}

This code "claims" to swap values of x and y. I gather that this
claims holds true only if (x-y) gets evaluated before (x==y). Since
there is no sequence point at (+), hence I assume that the order of
evaluation of operands of (+) is unspecified and hence the claim's
isn't always true. Is that correct?  Or is there a sequence point at
(x=y) which forces the evaluation of (x-y) before it, there by making
the claim always true?

void swap(int &x, int &y)
{
x = x^y;
y = x^y;
x = x^y;
}
 
J

James Kanze

Btw, I wonder if the compiler is allowed to skip evaluating
subexpressions if it knows that the result will not affect
anything. For example if you have something like:
int value = expression1 * expression2;
and expression1 evaluates to 0, then expression2 will have no
effect on the result. Is the compiler allowed to skip
evaluating expression2 in that case?

In general, the compiler can do whatever it likes, as long as
the "observable behavior" of the program corresponds to what the
standard requires. Depending on the surrounding code, if
expression1 is a constant expression evaluating to 0, the
compiler might eliminate the variable "value" completely. If
expression2 contains a call to a function with output, however,
that function must still be called, even if the variable is
eliminated. (It may be called at any time after the previous
output, and before the next output, however. It doesn't have to
be called precisely here.)
 
J

Juha Nieminen

Bo Persson said:
If expression2 has no side effects, we cannot tell and the compiler
can do whatever it likes.

However for something like

int value = 0 * print(x);

the value of x have better be printed.

Well, that's what I'm asking. Does the standard say that it "better be
printed", or does it say that the compiler can skip it?

After all, there are other situations where compilers are allowed to
skip executing code, even in cases where the code must exist (for
example the situations where the compiler can skip calling a copy
constructor, even though one must exist).
 
B

Bo Persson

Juha said:
Well, that's what I'm asking. Does the standard say that it
"better be printed", or does it say that the compiler can skip it?

It doesn't phrase it exactly that way :), but says that observable
side effects must be produced.
After all, there are other situations where compilers are allowed
to skip executing code, even in cases where the code must exist (for
example the situations where the compiler can skip calling a copy
constructor, even though one must exist).

The copy constructor is special, in that the implementation may assume
that it just copies and for example "elide" the copying of a return
value. In that special case, a print(x) in the copy constructor would
be skipped.


Bo Persson
 
D

Daniel Pitts

int
main()
{
int a = 42;
swap(a, a);
std::cout<< a<< std::endl;
return 0;
}

Doesn't work.

void swap(int &x, int&y) {
int tmp = x;
x = y;
y = tmp;
}

There, done, why bother with anything else? Are you running on an
architecture which has only 64 bytes of free memory?

Actually, isn't there a std::swap template function? Why not use that? I
bet it is better :)
 
J

Johannes Schaub (litb)

Johannes said:
it, while the former read is not
for determining the value to store. Thus you have behavior undefined. This
also applies to C++0x, which allows more things with defined behavior

++i = 0; // defined by c++0x, undefined by C++03
++ ++i; // defined by c++0x, undefined by C++03
i = ++i; // defined by c++0x, undefined by C++03

Please disregard the last one. That's still undefined in C++0x it seems.
Value computation of the left i is not sequenced relative to the side effect
of "++i".
 

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

Forum statistics

Threads
473,778
Messages
2,569,605
Members
45,238
Latest member
Top CryptoPodcasts

Latest Threads

Top