A couple questions

S

Snis Pilbor

Hello,

First question: besides the syntactical difference of one having
to be enclosed in brackets in some situations, are there any subtler
differences between (say)
x=(some expression), y=(some expression);
and
x=(some expression); y=(some expression); ?

What about sequence points? For example, would the phrase "i++, i++;"
be well-defined? Is there any guarantee about which computation the
program will perform first, for example is "x=x+1, x=x*2;" a
well-defined phrase? (intuitively I would assume so and that it would
go left to right but I'd like to be sure)


Second question: in one project I maintain, the guy is fond of
using >> and << for routine division/multiplication. For instance
instead of size *= 2, he will write size <<= 1. My question is, is
there a practical reason for doing this, for routine situations besides
actual bit twiddling? I know << is usually faster than *, but I always
assumed any compiler worth a hill of beans would easily know to
optimize something like "size *= 2" as much as possible anyway?

Thanks for helping out, you guys rock =)

-Snis P.
 
A

Andrew Poelstra

Hello,

First question: besides the syntactical difference of one having
to be enclosed in brackets in some situations, are there any subtler
differences between (say)
x=(some expression), y=(some expression);
and
x=(some expression); y=(some expression); ?

Well, the first is a single expression returning the value of y. The
second is two separate expressions and can't be used as, say,
c = (x=a, y=b); which gives c the value of b.
What about sequence points? For example, would the phrase "i++, i++;"
be well-defined? Is there any guarantee about which computation the
program will perform first, for example is "x=x+1, x=x*2;" a
well-defined phrase? (intuitively I would assume so and that it would
go left to right but I'd like to be sure)

I believe that it is well-defined. However, I don't think that the order
of computations is guaranteed. I don't claim to be an expert, though, so
you should wait for a more knowledgable person to answer.

I do know, however, that most well-written code shouldn't care what the
order of computations is, because a maintenance programmer shouldn't be
expected to know. Well-written code should be clear and be evaluated in
one (obvious) way.
Second question: in one project I maintain, the guy is fond of
using >> and << for routine division/multiplication. For instance,
instead of size *= 2, he will write size <<= 1. My question is, is
there a practical reason for doing this, for routine situations besides
actual bit twiddling?

Tsk, tsk, tsk. There is no reason for that, except to make the code
unreadable. Tomorrow I might want to multiply by 12 instead of 8; with
multiplication that involves changing one number.

y *= 8; /* In the case that the grommet fails to widge consistently,
multiply by 13 to compensate. Shouldn't be an issue with
the new vendor, though. */
x <<= 2; /* If we're interfacing with DeviceBoy revision F, we need to
shift by 4 to make room for the LCD brightness flags. We
should be compatible before the next version ships. */

See how using an inappropriate operator would make maintenance more
difficult? You should correct your errant colleague.
I know << is usually faster than *

No you don't.
, but I always
assumed any compiler worth a hill of beans would easily know to
optimize something like "size *= 2" as much as possible anyway?

Indeed it will.
Thanks for helping out, you guys rock =)

No problem. :)
 
E

Eric Sosman

Snis Pilbor wrote On 07/27/06 14:49,:
Hello,

First question: besides the syntactical difference of one having
to be enclosed in brackets in some situations, are there any subtler
differences between (say)
x=(some expression), y=(some expression);
and
x=(some expression); y=(some expression); ?

Well, you can throw parentheses around the first one
(not enclosing the semicolon) and use it as part of a
still larger expression:

z = (x = some_expression, y = some_expression) + 42;

.... which you could not do with a pair of complete statements.
What about sequence points?

There are sequence points at the comma and at the
semicolons.

For example, would the phrase "i++, i++;"
be well-defined?

Yes.
Is there any guarantee about which computation the
program will perform first, for example is "x=x+1, x=x*2;" a
well-defined phrase? (intuitively I would assume so and that it would
go left to right but I'd like to be sure)

You assume correctly. However, the fact that you find it
necessary to assume is troubling; *all* this stuff should be
in your C textbook or reference or whatever. If you don't
have such a thing, you should.
Second question: in one project I maintain, the guy is fond of
using >> and << for routine division/multiplication.

Oh, no! Again? Didn't we just *do* this? Didn't we just
do this for the umpteenth time? Go Google it: just pick any
ten threads at random and you'll have a better-than-even chance
of seeing this particular Apple of Discord on one or another of
its all-too-frequent trips down the table.
 
T

Tak-Shing Chan

I believe that it is well-defined. However, I don't think that the order
of computations is guaranteed. I don't claim to be an expert, though, so

The order is guaranteed. However, be careful not to confuse
the comma operator with comma-separated lists.

Tak-Shing
 
F

Flash Gordon

Snis said:
Hello,

First question: besides the syntactical difference of one having
to be enclosed in brackets in some situations, are there any subtler
differences between (say)
x=(some expression), y=(some expression);

The above returns a value. So you could do:
z = x=(some expression), y=(some expression);
and
x=(some expression); y=(some expression); ?

Obviously this is different.
What about sequence points? For example, would the phrase "i++, i++;"
be well-defined? Is there any guarantee about which computation the
program will perform first, for example is "x=x+1, x=x*2;" a
well-defined phrase? (intuitively I would assume so and that it would
go left to right but I'd like to be sure)

The comma operator (as opposed to the comma used to separate arguments
passed to a function) is a sequence point and guarantees the left
argument is evaluated first.
Second question: in one project I maintain, the guy is fond of
using >> and << for routine division/multiplication. For instance
instead of size *= 2, he will write size <<= 1. My question is, is
there a practical reason for doing this, for routine situations besides
actual bit twiddling? I know << is usually faster than *, but I always
assumed any compiler worth a hill of beans would easily know to
optimize something like "size *= 2" as much as possible anyway?

Many years ago there was sometimes an advantage. However, for a long
time compilers have been intelligent enough to use a shift where it is
appropriate (sometimes doing a multiply will be faster).

Using a shift, on the other hand, has a number of disadvantages. Right
shifting a negative number will not do a division by a power of two on
*all* systems. Shifting when you intend multiplication/division is less
clear to subsequent human readers.

So I would *always* use multiplication or division when that is what I
mean unless it is *proved* to be a problem in that specific instance.
 
A

Andrey Tarasevich

Snis said:
...
First question: besides the syntactical difference of one having
to be enclosed in brackets in some situations, are there any subtler
differences between (say)
x=(some expression), y=(some expression);
and
x=(some expression); y=(some expression); ?

Assuming that both are complete statements (they end in ';' in your example),
there's no difference between the two.
What about sequence points?

',' operator produces a sequence point, so there's no problem here.
For example, would the phrase "i++, i++;"
be well-defined?
Yes.

Is there any guarantee about which computation the
program will perform first, for example is "x=x+1, x=x*2;" a
well-defined phrase?

The left-hand side is evaluated first. As dictated by the sequence point, all
side-effects of the LHS take place before the evaluation of RHS begins.
(intuitively I would assume so and that it would
go left to right but I'd like to be sure)

That's indeed how it would go.
Second question: in one project I maintain, the guy is fond of
using >> and << for routine division/multiplication. For instance
instead of size *= 2, he will write size <<= 1. My question is, is
there a practical reason for doing this, for routine situations besides
actual bit twiddling?

No, no reason (unless you are using a really weird compiler).

Also note that for negative left operand ('size') the effects of 'size >> 1' and
'size / 2' are not necessarily identical. In C90 both are
implementation-defined. In C99 the latter is required to round toward 0, while
the former is still implementation-defined.
I know << is usually faster than *,

No. '<<' and '*' are C language operators. The notion of 'speed' is not
applicable to them. Apparently, you are identifying these operators with
"similar" CPU instructions of you favorite hardware platform (say, 'shl' and
'mul'), believing that there's a 1:1 match between them. This is not correct in
general case. When it comes to such simple expressions, modern compilers usually
easily recognize equivalent expressions and generate identical (optimal) machine
instructions for them, i.e. 'size *= 2' and 'size <<= 1' will normally produce
the same code and give you the same efficiency. What often comes as a surprise
to such manual-optimization fans is that the most optimal code for both 'size *=
2' and 'size <<= 1' does not use neither CPU's multiply operation nor CPU's
shift operation, but instead uses something much less obvious, like some form of
CPU's load-effective-address operation.
 
C

Chris Torek

The above returns a value. So you could do:
z = x=(some expression), y=(some expression);

Yes -- but note that:

z = x = 4, y = 5;

parses as:

(z = (x = 4)), (y = 5);

since the "=" operator binds more tightly than the "," operator.
Obviously this is different.

In this case, it would give the same result:

z = x = 4; y = 5;

still sets both z and x to 4, and y to 5.
The comma operator (as opposed to the comma used to separate arguments
passed to a function) is a sequence point and guarantees the left
argument is evaluated first.

Yes. However, if (x = 4, y = 5) is parenthesized and the entire
thing is put into a larger expression, one can obtain undefined
behavior:

x = x + (x = 4, y = 5); /* undefined */

The version with the semicolons is not an expression, so it cannot
be parenthesized and used as one.
Many years ago there was sometimes an advantage. However, for a long
time compilers have been intelligent enough to use a shift where it is
appropriate (sometimes doing a multiply will be faster).

Even Dennis Ritchie's original PDP-11 C compiler would turn "x *
constant-power-of-2" into "x << log2(that)", if I remember right.
Modern compilers are pretty good at this; "x = (x * 10) + (c -
'0')" turns into a pair of non-obvious VAX instructions under GCC:

# if x is in r3 and c is in r2
moval r3[r3], r3
movaw -48(r2)[r3], r3
Using a shift, on the other hand, has a number of disadvantages. Right
shifting a negative number will not do a division by a power of two on
*all* systems. Shifting when you intend multiplication/division is less
clear to subsequent human readers.

So I would *always* use multiplication or division when that is what I
mean unless it is *proved* to be a problem in that specific instance.

You can also help out the compiler by using "unsigned" if the value
will never be negative:

unsigned int x;
...
x /= 32;

usually allows the compiler to emit "x >>= 5" internally, because
here a shift *does* give the same answer as a divide.

(GCC will still replace divides when appropriate: some turn into
shift-and-fix-up, others turn into reciprocal multiply.)
 
C

Christopher Benson-Manica

(WRT to x=x+1, x=x*2;)
I believe that it is well-defined. However, I don't think that the order
of computations is guaranteed. I don't claim to be an expert, though, so
you should wait for a more knowledgable person to answer.

You are correct on the first point; however, the order of computations
is guaranteed, at least per 6.5.17 of n869:

"The left operand of a comma operator is evaluated as a void expression;
there is a sequence point after its evaluation. Then the right operand is
evaluated; the result has its type and value."
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top