C/C++ Ambiguity in Order of Evaluation

R

Richard Heathfield

Barry Schwarz said:

However, the typical example of a strcpy
work-alike provides an example:
char * my_copy(char *dest, const char *src)
{char *rtn = dest;
while (*dest++ = *src++;)
;

You could profitably lose a semicolon from inside that while loop
header.

<snip>
 
C

CBFalconer

Harald said:
.... snip ...

Okay, how would you then rewrite

if (p != NULL && p->data == 1234) {
/* A */
} else {
/* B */
}

Why should you even consider rewriting it? (Your first version was
WRONG, BAD, FOOBAR, etc.)
 
R

Rasjid

That depends on whether the manual is intended to have any educational
value. Repetition, examples, and alternate expositions can be
valuable.

The learning process to acquire a knowledge of C should never be
as :-
if (learn_from_C_reference_manual == SUCCESS);
else if (learn_from_college_lecturer == SUCCESS);
else if (learn_from_online_tutorial == SUCCESS);
else if (learn_from_Bjarne_C++ == SUCCESS);
else{
cout << "Give Up<<'\n'<<fflush;
}
Except for the few operators with implied or explicit sequence points,
it should not be. If it is, what are you going to do when the next
upgrade to the compiler changes the order? In fact, most places where
people think it matters are actually prohibited as undefined behavior.
Accepted, and therefore the C panelist did a good job!
I can't tell if I've seen all the messages in this thread but I don't
remember any such request. However, the typical example of a strcpy
work-alike provides an example:
char * my_copy(char *dest, const char *src)
{char *rtn = dest;
while (*dest++ = *src++;)
;
return rtn;}
Is the ++ applied to the pointer or the object pointed to? If you
don't know the precedence and associativity of the operators, how
would you figure it out?
My carelessness. Fortunately I post here only after learning rules on
precedence of operators is a must. My request was for a single example
where order of evaluation is determined by precedence of operators.

Rasjid
 
C

CBFalconer

Rasjid said:
.... snip ...

My carelessness. Fortunately I post here only after learning rules
on precedence of operators is a must. My request was for a single
example where order of evaluation is determined by precedence of
operators.

You have been told (and ignored) that no such thing exists.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

CBFalconer said:
Why should you even consider rewriting it? (Your first version was
WRONG, BAD, FOOBAR, etc.)

You shouldn't. The message that I replied to (which you snipped) claimed
that you should. That was clearly not what Richard meant (as he has also
replied) and my message was an attempt to point that out -- a not too good
attempt, it seems.
 
R

Richard Tobin

*a(c = g(y)) += b[f(x)];

Of course g() must be called before c is assigned...

What if the compiler can statically determine that g() always returns
zero?

There is a sequence point before procedure call, but I find the
wording on sequence points so confusing that I can't be sure what it
implies in this case - "no side effects of subsequent evaluations
shall have taken place", but what determines that the assignment
to c is a *subsequent* evaluation?

-- Richard
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Richard said:
Army1987 <[email protected]> said:
*a(c = g(y)) += b[f(x)];

Of course g() must be called before c is assigned...

What if the compiler can statically determine that g() always returns
zero?

And what if the compiler can statically determine that g() always returns c?
Does that mean it's allowed to set c to whatever it wants, and then call g?

In both your and my case, I'm confident the intended answer is just what
Army1987 claimed (though of course, if the visible behaviour remains the
same, the as-if rule applies), but I cannot find a definitive answer.
 
¬

¬a\\/b

x = a * b + c
can work as

t1 = a; t2 = b; t3 = c; t4 = t1 * t2; t5 = t4 * t3; x = t5;

ev=evalute

what about
t1=ev(a); t2=ev(b); t3=t1*t2; t4=ev(c); t5=t3+t4; x=t5;

what about x= ++a() * --b() + ++c();
t1=++ev(a()); t2=--ev(b()); t3=t1*t2; t4=++ev(c()); t5=t3+t4; x=t5;

and if function is more complex?

x=m>3?a:b;

t1=ev(m): if(t1>3) Return(ev(a))
else Return(ev(b))
 
M

Mark McIntyre

ev=evalute

what about
t1=ev(a); t2=ev(b); t3=t1*t2; t4=ev(c); t5=t3+t4; x=t5;

the semicolons introduce sequence points.
what about x= ++a() * --b() + ++c();

Error - you can't increment a function.
t1=++ev(a()); t2=--ev(b()); t3=t1*t2; t4=++ev(c()); t5=t3+t4; x=t5;

Ditto.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
O

Old Wolf

No, it doesn't, except accidentally. For example, it's hard to come up
with an order of evaluation for x * y + z that doesn't do the
multiplication before it does the addition.

An RPN-style evaluator might push z, then push x and y,
then mult, then add.
 
K

Keith Thompson

Old Wolf said:
An RPN-style evaluator might push z, then push x and y,
then mult, then add.

Which *does* do the multiplication before it does the addition.
 
O

Old Wolf

Which *does* do the multiplication before it does the addition.

Sorry, I took R.H.'s comment to read: evaluates
the arguments of the multiplication before
evaluating those of the addition.
 
O

Old Wolf

If your reply is just plain text, you don't need a preview.

I used to use Google Groups preview feature to
check that my lines were short enough so that
others didn't see a long-short-long-short wrapping
effect when reading my posts. Since they removed
that option, I just have to cross my fingers..:)
 
R

Richard Tobin

For example, it's hard to come up
with an order of evaluation for x * y + z that doesn't do the
multiplication before it does the addition.

It might use a multiply-and-add instruction which does them both at
once.

(I assume multiply-and-add works domething like this: to do 12*23+45
it does 10*23 + 2*23 + 45, so that the multiplication might at least
not be finished before the addition.)

-- Richard
 
F

Flash Gordon

Richard Tobin wrote, On 25/06/07 09:15:
It might use a multiply-and-add instruction which does them both at
once.

(I assume multiply-and-add works domething like this: to do 12*23+45
it does 10*23 + 2*23 + 45, so that the multiplication might at least
not be finished before the addition.)

On the processors I've used with a MAC instruction, the add is the
result of the previous multiple not the current one, so it can be done
in parallel with the multiple. So if you had
a * b + a * c + a * d;
You could implement it as
ZAC ; Zero the accumulator
LT a ; Load a in to the T register
MPY b ; Multiple b by the T register
MAC c ; Add the product to the accumulator and multiple c * T
MAC d ; Add the product to the accumulator and multiple d * T
APAC ; Add the product to the accumulator

So here an add is always occurring at the same time (same clock cycle)
as a multiply, but the add is always the result of an earlier multiply.

The above was for the Texas Instruments TMS320C2x series of processors.

What I have done with hand coded assembler which is even screwier was
using some of the address registers for add/subtract whilst using the
accumulator & multiplier for other things. Because the addressing was
done in an earlier pipeline stage to the ALU, multiplier and
transferring data to/from the address registers, it ended up with
instructions using data in address registers appearing *after*
instructions overwriting the data in the register, although the parts
actually executed in the correct order. This was on a TMS320C80, and I
would not have written code like that if it was not for the fact that
even using every trick I could come up with we still did not have enough
processing power (I did it so it would work as much as possible with
what we had).

I don't know how much the compilers make use of these tricks, I know the
TMS320C80 C compiler was bad, but I generally found the TMS320C2x
compiler did a good enough job. However, the compiler writers *could* do
screwy things like this if they were clever enough.
 
R

Richard Heathfield

Flash Gordon said:
Richard Tobin wrote, On 25/06/07 09:15:

On the processors I've used with a MAC instruction, the add is the
result of the previous multiple not the current one, so it can be done
in parallel with the multiple. So if you had
a * b + a * c + a * d;
You could implement it as
ZAC ; Zero the accumulator
LT a ; Load a in to the T register
MPY b ; Multiple b by the T register
MAC c ; Add the product to the accumulator and multiple c * T
MAC d ; Add the product to the accumulator and multiple d * T
APAC ; Add the product to the accumulator

So here an add is always occurring at the same time (same clock cycle)
as a multiply, but the add is always the result of an earlier
multiply.

A *really* clever compiler, if it were sure that no overflows would
result, could translate this to:

MOV T, b
ADD T, c
ADD T, d
MUL T, a

thus doing the adds before the multiply, QED.
 
F

Flash Gordon

Richard Heathfield wrote, On 25/06/07 20:54:
Flash Gordon said:


A *really* clever compiler, if it were sure that no overflows would
result, could translate this to:

MOV T, b
ADD T, c
ADD T, d
MUL T, a

thus doing the adds before the multiply, QED.

It would have to be very clever, since the processor cannot add to the T
register, nor can it multiply by the contents of the accumulator. I'm
talking about a real processor with a MAC instruction. As far is the
standard is concerned yes, it could do it your way.
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top