what is the right value about a = a++;

  • Follow


in GCC and VS2008
the fllow code

int a = 0, b;
b = a = a++;
printf("%d, %d\n", a, b);

result is : 1, 0

in Java

they are all 0.


0
Reply lujnan (3) 2/6/2012 8:10:00 AM

On 6 helmi, 10:10, lujnan <luj...@gmail.com> wrote:
> in GCC and VS2008
> the fllow code
>
> int a = 0, b;
> b = a = a++;
> printf("%d, %d\n", a, b);
>
> result is : 1, 0
>
> in Java
>
> they are all 0.


I think that a = a++ means
the following: first a = a,
and then you increase a by 1.
So in my opinion, the
statement should equal to
a = a+1, or a++.

However, in the statement
b = a = a++, the case is
that first you insert a to
be and then a++ to a (a to
a and then increase it by
1). Thus, b equals 0 and
a equals 1.

From the aforementioned
follows that Java sucks
and GCC sucks less.
0
Reply camu.umac (1) 2/6/2012 8:28:18 AM


On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
> b = a = a++;

The question is posted in this group many times. 
Read the FAQ.  The result is undefined - that is, 
it is DEFINED to be undefined.  That means it is 
okay for the result to be different in different 
compilers, and it is even okay for it to be 
different in the same compiler in different 
places or at different times.
-- 

0
Reply bert.hutchings (56) 2/6/2012 9:45:13 AM

On Feb 6, 5:45=A0pm, bert <bert.hutchi...@btinternet.com> wrote:
> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
> > b =3D a =3D a++;
>
> The question is posted in this group many times.
> Read the FAQ. =A0The result is undefined - that is,
> it is DEFINED to be undefined. =A0That means it is
> okay for the result to be different in different
> compilers, and it is even okay for it to be
> different in the same compiler in different
> places or at different times.
> --

maybe it shows the c world is not perfect. in this point i like the
define of java.
Why C Standards Committee does not constrain this case.
0
Reply lujnan (3) 2/6/2012 10:33:24 AM

> b = a = a++;
> printf("%d, %d\n", a, b);

a=a++ or a=++a
The above statement when compiled results different in different
compilers.
So, such expressions are undefined.
0
Reply slashqb (1) 2/6/2012 10:35:49 AM

On Feb 6, 10:33=A0am, lujnan <luj...@gmail.com> wrote:

> maybe it shows the c world is not perfect. in this point i like the
> define of java.
> Why C Standards Committee does not constrain this case.

First case: a =3D a++;
Well, that's just pointless code.

Second case: *p =3D (*q)++;
If p and q are different, then the assignment to *p and the increment
of *q can happen in arbitrary order. The compiler can do both
operations in the order that produces the fastest code, or just do
both operations in arbitrary order. It would be just daft to force the
compiler to use a particular order and possibly producing slower code
just for the totally unlikely case that p and q are the same, that is
just daft.
0
Reply christian.bau1 (402) 2/6/2012 10:57:54 PM

Ruben Mikkonen <camu.umac@gmail.com> writes:
[...]
> I think that a = a++ means the following: first a = a, and then you
> increase a by 1.  So in my opinion, the statement should equal to a =
> a+1, or a++.
[...]

This is not a matter of opinion.  As has been stated countless times,
the behavior is undefined -- not just the result of the expression,
or the values assigned to a, but the behavior of any program that
evaluates that expression.  It can do exactly what you expect it
to do, it can crash your program, it can reformat your hard drive.

What "a = a++" really means is that the person who wrote it
does not understand C well enough, and has not read the FAQ at
<http://c-faq.com>.  (Both problems are curable).

Whatever you intended to do, there's certainly a better way to
express it.  If you just want to increment a, just write "a++";
that already assigns the new value to a, so there's no need for an
assignment operator in addition to that.  The "++" operator is not
just a fancy way of writing "+ 1".

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21467) 2/7/2012 5:27:15 AM

lujnan <lujnan@gmail.com> writes:

> in GCC and VS2008
> the fllow code
>
> int a = 0, b;
> b = a = a++;
> printf("%d, %d\n", a, b);
>
> result is : 1, 0
>
> in Java
>
> they are all 0.

Keep in mind C and Java are not the same language, so you can't expect
them to have the same semantics.  The results you got for the C
compilers are correct (for C).  I would assume the result you got for
Java is also correct (for Java), but I don't use Java so I don't really
know.
0
Reply pfeiffer (616) 2/7/2012 5:37:05 AM

Keith Thompson <kst-u@mib.org> writes:

> Ruben Mikkonen <camu.umac@gmail.com> writes:
> [...]
>> I think that a = a++ means the following: first a = a, and then you
>> increase a by 1.  So in my opinion, the statement should equal to a =
>> a+1, or a++.
> [...]
>
> This is not a matter of opinion.  As has been stated countless times,
> the behavior is undefined -- not just the result of the expression,
> or the values assigned to a, but the behavior of any program that
> evaluates that expression.  It can do exactly what you expect it
> to do, it can crash your program, it can reformat your hard drive.
>
> What "a = a++" really means is that the person who wrote it
> does not understand C well enough, and has not read the FAQ at
> <http://c-faq.com>.  (Both problems are curable).
>
> Whatever you intended to do, there's certainly a better way to
> express it.  If you just want to increment a, just write "a++";
> that already assigns the new value to a, so there's no need for an
> assignment operator in addition to that.  The "++" operator is not
> just a fancy way of writing "+ 1".

Urrgh.  I stand corrected (in the past I've made fruitless tries at
cancelling posts I've made that are wrong; since there's no real point
I'll just recognize that I was wrong now, and ignore the corrections to
my post that are sure to follow).
0
Reply pfeiffer (616) 2/7/2012 5:39:41 AM

On 2/6/2012 03:10, lujnan wrote:
> in GCC and VS2008
> the fllow code
>
> int a = 0, b;
> b = a = a++;
> printf("%d, %d\n", a, b);
>
> result is : 1, 0
>
> in Java
>
> they are all 0.
>

In this context, your:

   a++

expression is similar to the expression:

   ((a = a + 1), (a - 1))

except that there is no sequence point in 'a++' and there is only one 
read access in 'a++' and one write access in 'a++'.

Behold the following events for the following expressions:

   a++

A.1. Read the value of 'a' before the next sequence point
A.2. Increment the value of 'a' (a write) before the next sequence point

   a = ...

B.1. Evaluate the expression '...' before the next sequence point
B.2. Store that value to 'a' before the next sequence point

   b = ...

C.1. Evaluate the expression '...' before the next sequence point
C.2. Store that value to 'b' before the next sequence point

Note the ordering.

So we get the following order for your special line:

   b = a = a++;

1. Evaluate the expression 'a = a++' (C.1)
2. Evaluate the expression 'a++' (B.1)
3. Read the value of 'a' (A.1)
?. Any time now or before the next sequence point, increment the value 
of 'a' (A.2)
?. Any time now or before the next sequence point, store the value to 
'a' (B.2)
4. There's no time left before the next sequence point, so we must store 
the value to 'b' (C.2)

Note how #4 is ordered relative to #1, #2, #3, but unordered relative to 
the two '?' operations.  The '?' operations and #4 must occur after #3, 
but can occur in any order.

Since there are two "write" operations to 'a' that can potentially occur 
at the same time, that results in undefined behaviour.

Maybe the increment of 'a' happens first.  Maybe the other store to 'a' 
happens first.  Maybe they happen at exactly the same time and the 
computer crashes.  Other "maybes" are possible too, since there are no 
defined limits to what can happen.
0
Reply sha0.miller (876) 2/7/2012 6:18:35 AM

On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan <lujnan@gmail.com>
wrote:

>On Feb 6, 5:45�pm, bert <bert.hutchi...@btinternet.com> wrote:
>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>> > b = a = a++;
>>
>> The question is posted in this group many times.
>> Read the FAQ. �The result is undefined - that is,
>> it is DEFINED to be undefined. �That means it is
>> okay for the result to be different in different
>> compilers, and it is even okay for it to be
>> different in the same compiler in different
>> places or at different times.
>> --
>
>maybe it shows the c world is not perfect. in this point i like the
>define of java.
>Why C Standards Committee does not constrain this case.

They did.  They put explicit text in the language standard that
specifically states that this type of expression produces undefined
behavior.

Since one group of people with significant input to the standard is
the compiler writers, the committee accepted their assertion that
forcing the compiler to diagnose most kinds of undefined behavior is
just not practical.

What more would you want and how much are you willing to pay for it?
Not just initial money outlay but also extended compile times,
additional diagnostics that require documentation, etc.  Since some
forms of undefined behavior can only be detected during execution, you
will also have larger program sizes and slower execution speeds.  "Be
careful what you wish for" is good advice.

-- 
Remove del for email
0
Reply schwarzb3978 (1358) 2/7/2012 6:50:31 AM

On 2012-02-07, Joe Pfeiffer <pfeiffer@cs.nmsu.edu> wrote:
> Keep in mind C and Java are not the same language, so you can't expect
> them to have the same semantics.  The results you got for the C
> compilers are correct (for C).  I would assume the result you got for
> Java is also correct (for Java), but I don't use Java so I don't really
> know.

The result is correct for Java, which as a well-defined evaluation order. For C,
there is no "correct" result.  An expected result is not a correct result.
0
Reply kaz15 (1129) 2/7/2012 7:22:54 AM

On 2012-02-07, Barry Schwarz <schwarzb@dqel.com> wrote:
> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan <lujnan@gmail.com>
> wrote:
>
>>On Feb 6, 5:45 pm, bert <bert.hutchi...@btinternet.com> wrote:
>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>> > b = a = a++;
>>>
>>> The question is posted in this group many times.
>>> Read the FAQ.  The result is undefined - that is,
>>> it is DEFINED to be undefined.  That means it is
>>> okay for the result to be different in different
>>> compilers, and it is even okay for it to be
>>> different in the same compiler in different
>>> places or at different times.
>>> --
>>
>>maybe it shows the c world is not perfect. in this point i like the
>>define of java.
>>Why C Standards Committee does not constrain this case.
>
> They did.  They put explicit text in the language standard that
> specifically states that this type of expression produces undefined
> behavior.
>
> Since one group of people with significant input to the standard is
> the compiler writers, the committee accepted their assertion that
> forcing the compiler to diagnose most kinds of undefined behavior is
> just not practical.

I don't want diagnostics; I want strict left to right evaluation order
of operands and subexpressions that complete their side effects before
yielding a value.

Making it unspecified and then trying to catch violations is an
example of silly make-work: creating complexity and then trying
to conquer it, for no benefit.

This unspecified order of evaluation is a throwback to 1980,
when *dst++ = *src++ generated better code than *dst = *src; src++; dst++.

Once upon a time, you had to stuff multiple side effects into the same
expression to get better code because the compiler was following some
naive syntax-directed translation scheme.

> forms of undefined behavior can only be detected during execution, you
> will also have larger program sizes and slower execution speeds.

Wouldn't /that/ be dumb, given that the (now false) rationale for this
unspecified evaluation order business is to get faster code without
working hard in the compiler.
0
Reply kaz15 (1129) 2/7/2012 8:15:17 AM

> I don't want diagnostics; I want strict left to right evaluation order
> of operands and subexpressions that complete their side effects before
> yielding a value.

i agree with your point of view.

0
Reply lujnan (3) 2/7/2012 8:31:05 AM

On Feb 6, 10:35=A0am, Slash QB <slas...@gmail.com> wrote:
> > b =3D a =3D a++;
> > printf("%d, %d\n", a, b);
>
> a=3Da++ or a=3D++a
> The above statement when compiled results different in different
> compilers.
> So, such expressions are undefined.

isn't that the other way round

    the statement is undefined
    =3D>
    compilers are permitted to produce different answers
   (or trap or crash or anything else weird the compiler writer feels
like)
0
Reply nick_keighley_nospam (4574) 2/7/2012 11:07:55 AM

On 02/06/2012 05:33 AM, lujnan wrote:
> On Feb 6, 5:45�pm, bert <bert.hutchi...@btinternet.com> wrote:
>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>> b = a = a++;
>>
>> The question is posted in this group many times.
>> Read the FAQ. �The result is undefined - that is,
>> it is DEFINED to be undefined. �That means it is
>> okay for the result to be different in different
>> compilers, and it is even okay for it to be
>> different in the same compiler in different
>> places or at different times.
>> --
> 
> maybe it shows the c world is not perfect. in this point i like the
> define of java.
> Why C Standards Committee does not constrain this case.

Because they don't want you to write code like this. It serves no useful
purpose to write code this way. I can think of two plausible defined
behaviors for a=a++. One is equivalent to a++, so why bother with the
"a="? The other is equivalent to a = a, so why bother writing anything
at all?

The rule violated by this code is much more general than that, and
includes cases that cannot be so easily dismissed. But it is almost
always the case that the intended behavior of any code violating that
rule can be more clearly expressed by separating it into two or more
separate statements, none of which violate that rule.
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/7/2012 12:42:50 PM

lujnan <lujnan@gmail.com> writes:
>> I don't want diagnostics; I want strict left to right evaluation order
>> of operands and subexpressions that complete their side effects before
>> yielding a value.
>
> i agree with your point of view.

Then you don't want C.

There are valid reasons for the way C leaves some expression evaluations
undefined.  It gives compilers freedom to perform certain optimizations,
which makes for faster code.  And code whose behavior is undefined tends
to be unclear, and would better be written in a different way whose
behavior is well defined.

Even in a language that defines its behavior, "a = a++" is bad code.


-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21467) 2/7/2012 5:07:27 PM

On 2012-02-07, James Kuyper <jameskuyper@verizon.net> wrote:
> On 02/06/2012 05:33 AM, lujnan wrote:
>> On Feb 6, 5:45�pm, bert <bert.hutchi...@btinternet.com> wrote:
>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>> b = a = a++;
>>>
>>> The question is posted in this group many times.
>>> Read the FAQ. �The result is undefined - that is,
>>> it is DEFINED to be undefined. �That means it is
>>> okay for the result to be different in different
>>> compilers, and it is even okay for it to be
>>> different in the same compiler in different
>>> places or at different times.
>>> --
>> 
>> maybe it shows the c world is not perfect. in this point i like the
>> define of java.
>> Why C Standards Committee does not constrain this case.
>
> Because they don't want you to write code like this. It serves no useful
> purpose to write code this way.

That particular instance (a = a++) serves no useful purpose. The instance
does not damn the class.

Does it serve no purpose that if I have f(..., g(), ... h()); I can
be assured that g is called before h?

Etc.

Even if a = a++ serves no useful purpose, suppose that I'm managing a
software project and someone writes that somewhere (not me, I wouldn't).
It sure would help me if a = a++ were to be reliable and compute the same
thing regardless of compiler, optimization setting or target.


> I can think of two plausible defined
> behaviors for a=a++. One is equivalent to a++, so why bother with the
> "a="? The other is equivalent to a = a, so why bother writing anything
> at all?

One particular choice of behavior stands out: the simple, recursive rule:

- evaluate each subexpression completely, includiing all of its side effects,
  before evaluating the parent expression.

- if an expression has several subexpressions, evaluate them left to right.

> But it is almost
> always the case that the intended behavior of any code violating that
> rule can be more clearly expressed by separating it into two or more
> separate statements, none of which violate that rule.

That's obviously only if you know what the behavior should be.

That's easy; just find out the whereabouts of the guy who wrote it
three years ago who no longer works here ...
0
Reply kaz15 (1129) 2/7/2012 5:21:11 PM

On Tue, 7 Feb 2012 00:31:05 -0800 (PST), lujnan <lujnan@gmail.com>
wrote:

>
>> I don't want diagnostics; I want strict left to right evaluation order
>> of operands and subexpressions that complete their side effects before
>> yielding a value.
>
>i agree with your point of view.

Do you drive your car into lakes?  Do you use a screwdriver as a
soldering iron?  Then why are you using a programming tool that
doesn't do what you want when you already know of one that does?

-- 
Remove del for email
0
Reply schwarzb3978 (1358) 2/7/2012 5:26:22 PM

On 2012-02-07, Keith Thompson <kst-u@mib.org> wrote:
> lujnan <lujnan@gmail.com> writes:
>>> I don't want diagnostics; I want strict left to right evaluation order
>>> of operands and subexpressions that complete their side effects before
>>> yielding a value.
>>
>> i agree with your point of view.
>
> Then you don't want C.

You could say that to anyone who is working on the next standard.

Those who worked on C11 didn't want C99, and those who worked on C99
didn't want C90.

> There are valid reasons for the way C leaves some expression evaluations
> undefined. 

No, there are not. There are only outdated beliefs rooted in computer
science shamanism.

Fact is, defined order is safe. Safety is the number one goal in engineering.

> It gives compilers freedom to perform certain optimizations,

No, it allows *programmers* to perform optimizations, when using
compilers from early 1980-something.

> which makes for faster code.  And code whose behavior is undefined tends

Modern compilers can rearrange code substantially, on a large scale,
way beyond the space between two sequence points.

> to be unclear, and would better be written in a different way whose

It's only unclear because it is undefined. If you have a rule like
subexpressions are evaluated from left to right, before parent expressions,
and each expression is fully evaluated before the next expression,
then all these expressions become perspiciously clear. Let's take
a[i] = i++. The main operator is =, so it is evaluated last.
a[i] is evaluated first because it is on the left. Then i++ is evaluated,
producing the prior value of i. Then that value is moved into a[i]
(the original a[i] of course: once a[i] is evaluated it ceases
to be a moving target.)

> behavior is well defined.

Yes, would better be. Would, should does not add up to will.

Code will not rewrite itself.

That ambiguous expression is sitting in the codebase somewhere, and you don't
even know. 

And the intent? It died with the guy who left the company several years ago and
then got run over by a bus.

You're out of your intellectual league here, Kiki.
0
Reply kaz15 (1129) 2/7/2012 5:31:23 PM

Kaz Kylheku <kaz@kylheku.com> writes:

> I don't want diagnostics; I want strict left to right evaluation order
> of operands and subexpressions that complete their side effects before
> yielding a value.

You could use Java.
-- 
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
0
Reply blp (3953) 2/7/2012 8:09:12 PM

On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
> On 2012-02-07, Barry Schwarz<schwarzb@dqel.com>  wrote:
>> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan<lujnan@gmail.com>
>> wrote:
>>
>>> On Feb 6, 5:45 pm, bert<bert.hutchi...@btinternet.com>  wrote:
>>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>>> b = a = a++;
[...]
> I don't want diagnostics; I want strict left to right evaluation order
> of operands and subexpressions that complete their side effects before
> yielding a value.

So, what you are really saying, is you want to eliminate most of C's 
optimization abilities, by restricting the order in which the expression 
*must* be evaluated, and side effects *must* be completed?

[...]

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/7/2012 8:12:53 PM

On 07-Feb-12 05:07, Nick Keighley wrote:
> On Feb 6, 10:35 am, Slash QB <slas...@gmail.com> wrote:
>>> b = a = a++;
>>> printf("%d, %d\n", a, b);
>>
>> a=a++ or a=++a
>> The above statement when compiled results different in different
>> compilers.
>> So, such expressions are undefined.
> 
> isn't that the other way round
> 
>     the statement is undefined
>     =>
>     compilers are permitted to produce different answers
>    (or trap or crash or anything else weird the compiler writer feels
> like)

Compilers existed prior to the standard, so their divergent behavior
could not possibly be blamed on a non-existent standard allowing it.

AIUI, the job of the ANSI committee was to document the language as it
existed, warts and all, rather than to create a new and perfect language
from scratch.  They did overstep that boundary on occasion, eg.
prototypes and (void *), but did so in ways that didn't break any
existing code.

As it turned out, different compilers treated "a=a++;" differently, and
the committee (rightly, IMHO) decided to allow them to continue with
that rather than break existing code that depended on a particular
compiler's ex post facto outlawed behavior.

While I've never taken an exhaustive inventory, I suspect most undefined
behavior in the standard could be traced to such a scenario.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/7/2012 9:19:16 PM

On 07-Feb-12 11:21, Kaz Kylheku wrote:
> On 2012-02-07, James Kuyper <jameskuyper@verizon.net> wrote:
>> I can think of two plausible defined
>> behaviors for a=a++. One is equivalent to a++, so why bother with the
>> "a="? The other is equivalent to a = a, so why bother writing anything
>> at all?
> 
> One particular choice of behavior stands out: the simple, recursive rule:
> 
> - evaluate each subexpression completely, includiing all of its side effects,
>   before evaluating the parent expression.
> 
> - if an expression has several subexpressions, evaluate them left to right.

Nice of you to dictate that people using systems that more efficiently
evaluate sub-expressions from right to left should suffer performance
degradation of all code, even in the majority of cases where the code is
well-written and therefore the order doesn't actually matter, simply
because it doesn't suit your sensibilities.

If you /need/ to know that "foo(bar(), baz());" calls bar() before
baz(), then just write "tmp=bar(); foo(tmp, baz());".  There is no need
to suffer that performance penalty, though, in the vast majority of
cases where it _doesn't_ matter.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/7/2012 9:24:03 PM

On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
<kenbrody@spamcop.net> wrote:

>On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>> On 2012-02-07, Barry Schwarz<schwarzb@dqel.com>  wrote:
>>> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan<lujnan@gmail.com>
>>> wrote:
>>>
>>>> On Feb 6, 5:45 pm, bert<bert.hutchi...@btinternet.com>  wrote:
>>>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>>>> b = a = a++;
>[...]
>> I don't want diagnostics; I want strict left to right evaluation order
>> of operands and subexpressions that complete their side effects before
>> yielding a value.
>
>So, what you are really saying, is you want to eliminate most of C's 
>optimization abilities, by restricting the order in which the expression 
>*must* be evaluated, and side effects *must* be completed?

Well, no, he isn't saying any such thing.  You just made it up.  The
fact that evaluation order in C is left to the compilers has very
little to do with optimization; it is a historical artifact that came
from endorsing existing practice when the ANSI standard was put
together.  Existing practice then was that compiler writers could do
evaluations in whatever they pleased and they did.

Granted there is no point in whining about C's lack of a well defined
evaluation.  C is what it is and "undefined" is pretty much carved in
stone.  But it has very little to do with optimization and a lot to do
with "that's the way things are; suck it up cupcake and live with it."

 

0
Reply cri (1432) 2/7/2012 9:50:17 PM

On 02/07/2012 04:19 PM, Stephen Sprunk wrote:
> On 07-Feb-12 05:07, Nick Keighley wrote:
>> On Feb 6, 10:35 am, Slash QB <slas...@gmail.com> wrote:
>>>> b = a = a++;
>>>> printf("%d, %d\n", a, b);
>>>
>>> a=a++ or a=++a
>>> The above statement when compiled results different in different
>>> compilers.
>>> So, such expressions are undefined.
>>
>> isn't that the other way round
>>
>>     the statement is undefined
>>     =>
>>     compilers are permitted to produce different answers
>>    (or trap or crash or anything else weird the compiler writer feels
>> like)
> 
> Compilers existed prior to the standard, so their divergent behavior
> could not possibly be blamed on a non-existent standard allowing it.

True; but the fact that different current compilers give different
results cannot be used to validly infer that the behavior is undefined.
The behavior could be implementation-defined, or simply unspecified, or
one of the compilers you're comparing could be non-conforming.

> AIUI, the job of the ANSI committee was to document the language as it
> existed, warts and all, rather than to create a new and perfect language
> from scratch.

It was neither of those things, and both. The committee was tasked with
creating a language specification which was supposed to honor many
different competing principles; some of the hardest work the committee
had to do was balancing those different principles. Some of those
principles, if taken in isolation, could have been interpreted as
calling for a "perfect" language. Other principles called for retaining
compatibility with existing practice.

Incidentally, it was made explicitly clear that "existing code is
important; existing implementations are not". I would presume that was
based upon the fact that, for any reasonably successful implementation
of C, the amount of code written for use on that implementation greatly
outweighed the amount of code required to implement it.

That principle became less important when existing practice was in
conflict with itself. The committee could have specified one particular
choice of behavior, rendering all implementations that didn't make that
choice non-conforming. They could have left the behavior unspecified,
with the range of permitted options wide enough to cover the variety of
existing practice. They could have declared that the behavior was
implementation-defined, requiring a conforming implementation to
document what behavior it chose. Or they could have declared the
behavior undefined, which by definition is compatible with anything that
any compiler might choose to do with the code. The committee did all
four of those things, in different contexts.
0
Reply jameskuyper (5151) 2/7/2012 10:00:45 PM

On 07-Feb-12 15:50, Richard Harter wrote:
> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
> <kenbrody@spamcop.net> wrote:
>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>> I don't want diagnostics; I want strict left to right evaluation order
>>> of operands and subexpressions that complete their side effects before
>>> yielding a value.
>>
>> So, what you are really saying, is you want to eliminate most of C's 
>> optimization abilities, by restricting the order in which the expression 
>> *must* be evaluated, and side effects *must* be completed?
> 
> Well, no, he isn't saying any such thing.  You just made it up.  The
> fact that evaluation order in C is left to the compilers has very
> little to do with optimization; it is a historical artifact that came
> from endorsing existing practice when the ANSI standard was put
> together.  Existing practice then was that compiler writers could do
> evaluations in whatever they pleased and they did.

No, they did evaluations in the order that made the most sense (i.e. had
the best performance) for their particular implementation--and
implementations vary.

For instance, varargs is more straightforward to implement with
right-to-left evaluation of arguments, at least with a stack-based
calling convention.  Order of evaluation may not matter for
register-based calling conventions, but if an implementation uses both,
it makes sense to use the same order.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/7/2012 10:51:17 PM

On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
<stephen@sprunk.org> wrote:

>On 07-Feb-12 15:50, Richard Harter wrote:
>> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
>> <kenbrody@spamcop.net> wrote:
>>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>>> I don't want diagnostics; I want strict left to right evaluation order
>>>> of operands and subexpressions that complete their side effects before
>>>> yielding a value.
>>>
>>> So, what you are really saying, is you want to eliminate most of C's 
>>> optimization abilities, by restricting the order in which the expression 
>>> *must* be evaluated, and side effects *must* be completed?
>> 
>> Well, no, he isn't saying any such thing.  You just made it up.  The
>> fact that evaluation order in C is left to the compilers has very
>> little to do with optimization; it is a historical artifact that came
>> from endorsing existing practice when the ANSI standard was put
>> together.  Existing practice then was that compiler writers could do
>> evaluations in whatever they pleased and they did.
>
>No, they did evaluations in the order that made the most sense (i.e. had
>the best performance) for their particular implementation--and
>implementations vary.
>
>For instance, varargs is more straightforward to implement with
>right-to-left evaluation of arguments, at least with a stack-based
>calling convention.  Order of evaluation may not matter for
>register-based calling conventions, but if an implementation uses both,
>it makes sense to use the same order.


Depends on which way your stack grows - with downward growth it's
usually easiest to evaluate varargs right-to-left, but for an upwards
growing stack left-to-right is usually easier.
0
Reply robertwessel2 (1339) 2/8/2012 4:49:40 AM

On 02/06/2012 05:33 AM, lujnan wrote:
> maybe it shows the c world is not perfect. in this point i like the
> define of java.

If you want Java, you know where to find it.

--Joel
0
Reply joelcsalomon (309) 2/8/2012 6:00:44 AM

On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
<stephen@sprunk.org> wrote:

>On 07-Feb-12 15:50, Richard Harter wrote:
>> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
>> <kenbrody@spamcop.net> wrote:
>>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>>> I don't want diagnostics; I want strict left to right evaluation order
>>>> of operands and subexpressions that complete their side effects before
>>>> yielding a value.
>>>
>>> So, what you are really saying, is you want to eliminate most of C's 
>>> optimization abilities, by restricting the order in which the expression 
>>> *must* be evaluated, and side effects *must* be completed?
>> 
>> Well, no, he isn't saying any such thing.  You just made it up.  The
>> fact that evaluation order in C is left to the compilers has very
>> little to do with optimization; it is a historical artifact that came
>> from endorsing existing practice when the ANSI standard was put
>> together.  Existing practice then was that compiler writers could do
>> evaluations in whatever they pleased and they did.
>
>No, they did evaluations in the order that made the most sense (i.e. had
>the best performance) for their particular implementation--and
>implementations vary.

You are not disagreeing with me.

>
>For instance, varargs is more straightforward to implement with
>right-to-left evaluation of arguments, at least with a stack-based
>calling convention.  Order of evaluation may not matter for
>register-based calling conventions, but if an implementation uses both,
>it makes sense to use the same order.

Well, yes, I know that.  However what you are talking about is a minor
micro-optimization at most.    

Historically the variations weren't a matter of performance - for the
most part the performance of the early compilers was less than
stellar.  The various choices in calling sequence conventions and in
parsing order were a mixture of convenience and ad hoc decisions.  The
order variations were an unalterable part of the language by the time
it came to standardization.    

In any event the idea that "most of C's optimization abilities" depend
upon not restricting evaluation order and side effect order is a wild
exaggeration.

  

    So, what you are really saying, is you want to eliminate most of
    C's optimization abilities, by restricting the order in which the
    expression *must* be evaluated, and side effects *must* be
    completed?

It was one thing to say that C is what it is, so suck it up and deal
with it.  It is quite 






0
Reply cri (1432) 2/8/2012 2:47:21 PM

On 07-Feb-12 22:49, Robert Wessel wrote:
> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
> <stephen@sprunk.org> wrote:
>> On 07-Feb-12 15:50, Richard Harter wrote:
>>> Well, no, he isn't saying any such thing.  You just made it up.  The
>>> fact that evaluation order in C is left to the compilers has very
>>> little to do with optimization; it is a historical artifact that came
>>> from endorsing existing practice when the ANSI standard was put
>>> together.  Existing practice then was that compiler writers could do
>>> evaluations in whatever they pleased and they did.
>>
>> No, they did evaluations in the order that made the most sense (i.e. had
>> the best performance) for their particular implementation--and
>> implementations vary.
>>
>> For instance, varargs is more straightforward to implement with
>> right-to-left evaluation of arguments, at least with a stack-based
>> calling convention.  Order of evaluation may not matter for
>> register-based calling conventions, but if an implementation uses both,
>> it makes sense to use the same order.
> 
> Depends on which way your stack grows - with downward growth it's
> usually easiest to evaluate varargs right-to-left, but for an upwards
> growing stack left-to-right is usually easier.

How would stack growth direction matter?  What matters for varargs is
that the first argument is on the top of the stack, regardless of which
way it grows.  If you push the arguments from right to left, the first
argument ends up on top.  You _could_ evaluate the arguments from left
to right, store them in registers or elsewhere in memory, and then push
from right to left, but why go through that extra effort?

(This, of course, assumes a stack-based calling convention for varargs
calls, as all of the ABIs I'm familiar with dictate, and possibly for
other calls.)

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/8/2012 8:08:40 PM

On 08-Feb-12 08:47, Richard Harter wrote:
> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
> <stephen@sprunk.org> wrote:
> 
>> On 07-Feb-12 15:50, Richard Harter wrote:
>>> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
>>> <kenbrody@spamcop.net> wrote:
>>>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>>>> I don't want diagnostics; I want strict left to right evaluation order
>>>>> of operands and subexpressions that complete their side effects before
>>>>> yielding a value.
>>>>
>>>> So, what you are really saying, is you want to eliminate most of C's 
>>>> optimization abilities, by restricting the order in which the expression 
>>>> *must* be evaluated, and side effects *must* be completed?
>>>
>>> Well, no, he isn't saying any such thing.  You just made it up.  The
>>> fact that evaluation order in C is left to the compilers has very
>>> little to do with optimization; it is a historical artifact that came
>>> from endorsing existing practice when the ANSI standard was put
>>> together.  Existing practice then was that compiler writers could do
>>> evaluations in whatever they pleased and they did.
>>
>> No, they did evaluations in the order that made the most sense (i.e. had
>> the best performance) for their particular implementation--and
>> implementations vary.
> 
> You are not disagreeing with me.

I disagree that they did "whatever they pleased"; they did what was best
for their particular implementation, for various definitions of "best".

>> For instance, varargs is more straightforward to implement with
>> right-to-left evaluation of arguments, at least with a stack-based
>> calling convention.  Order of evaluation may not matter for
>> register-based calling conventions, but if an implementation uses both,
>> it makes sense to use the same order.
> 
> Well, yes, I know that.  However what you are talking about is a minor
> micro-optimization at most.

It doesn't seem so minor, particularly for platforms where _every_ call
uses a stack-based calling convention.  Remember, we're talking about
long ago when compilers were rather dumb and most popular architectures
were register-starved.  That is the environment that ANSI was faced
with, and it would have been unreasonable to force the majority of
implementations to suffer a performance penalty for the questionable
benefit of left-to-right evaluation.

> Historically the variations weren't a matter of performance - for the
> most part the performance of the early compilers was less than
> stellar.

Of course; that was the state of the industry at the time.  All the more
reason not to make things worse.

> The various choices in calling sequence conventions and in
> parsing order were a mixture of convenience and ad hoc decisions.  The
> order variations were an unalterable part of the language by the time
> it came to standardization.

I think we can agree on this much: by the time ANSI looked at the
matter, it was too late to "fix" many of the behaviors that ended up
being called undefined, unspecified or implementation-defined because
doing so would have broken a lot of code that implicitly depended on a
particular implementation's pre-standard behavior.

> In any event the idea that "most of C's optimization abilities" depend
> upon not restricting evaluation order and side effect order is a wild
> exaggeration.

Optimization doesn't depend entirely on that particular gray area, but
gray areas in general provide implementations leeway to make more
aggressive optimizations because they lessen the impact of the "as if"
rule.  Allowing the meaning of "a=a++;" to change isn't helpful in
itself, but it may help the compiler optimize _something else_.

Also, most of those gray areas aren't terribly useful in the first place
and avoiding them generally results in clearer code anyway.  If _I_
can't figure out what "a=a++;" is supposed to mean, without possibly
resorting to the Standard, it's not important to me that the compiler
knows either because I won't write it in the first place!  My primary
audience is human, not machine.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/8/2012 8:29:05 PM

In article <bf40ad26-3199-441e-a524-acf38177273f@og8g2000pbb.googlegroups.com>,
lujnan  <lujnan@gmail.com> wrote:
>Why C Standards Committee does not constrain this case.

Because it's a dumb case.  You're not supposed to write that idiom,
and pointless constraints are a bad thing in a system where performance
is king.

-- 
	-Ed Falk, falk@despams.r.us.com
	http://thespamdiaries.blogspot.com/
0
Reply falk3260 (91) 2/8/2012 8:33:03 PM

On 2/7/2012 4:50 PM, Richard Harter wrote:
> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
> <kenbrody@spamcop.net>  wrote:
>
>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>> On 2012-02-07, Barry Schwarz<schwarzb@dqel.com>   wrote:
>>>> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan<lujnan@gmail.com>
>>>> wrote:
>>>>
>>>>> On Feb 6, 5:45 pm, bert<bert.hutchi...@btinternet.com>   wrote:
>>>>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>>>>> b = a = a++;
>> [...]
>>> I don't want diagnostics; I want strict left to right evaluation order
>>> of operands and subexpressions that complete their side effects before
>>> yielding a value.
>>
>> So, what you are really saying, is you want to eliminate most of C's
>> optimization abilities, by restricting the order in which the expression
>> *must* be evaluated, and side effects *must* be completed?
>
> Well, no, he isn't saying any such thing.  You just made it up.  The
> fact that evaluation order in C is left to the compilers has very
> little to do with optimization; it is a historical artifact that came
> from endorsing existing practice when the ANSI standard was put
> together.  Existing practice then was that compiler writers could do
> evaluations in whatever they pleased and they did.

Well, not having access to the Standards committee, I can only speculate. 
However, if evaluation order were the only thing at stake here, things would 
have been left as "unspecified" rather than "undefined".

Consider the fact that, in a "well behaved" program, the order of evaluation 
doesn't matter.  Consider, too, that an optimizer may change the order of 
evaluation to something more "efficient" on a given target platform.

The truth of the matter is, is that when, precisely, a side effect most 
efficiently takes effect, is very platform-dependent, and can even vary from 
expression to expression on a given platform.

> Granted there is no point in whining about C's lack of a well defined
> evaluation.  C is what it is and "undefined" is pretty much carved in
> stone.  But it has very little to do with optimization and a lot to do
> with "that's the way things are; suck it up cupcake and live with it."

In the 30+ years of programming in C, I don't believe I've ever had the need 
to write code which depended on side-effects being completed in "the right 
order" within a single statement.  Whether that's because I know that 
there's no such thing as "the right order", or because I never came across a 
scenario where that might be useful, I cannot say, but I'm leaning towards 
the latter.

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/8/2012 8:39:33 PM

In article <4f319955.234650417@text.giganews.com>,
Richard Harter <cri@tiac.net> wrote:
>
>Well, no, he isn't saying any such thing.  You just made it up.  The
>fact that evaluation order in C is left to the compilers has very
>little to do with optimization; it is a historical artifact that came
>from endorsing existing practice when the ANSI standard was put
>together.

Perhaps, but it can still have a lot to do with optimization.

Consider:

  b = (sqrt(sin(x)*cos(x))) * a;

If the compiler can guess that a is very likely to be zero, and that the
left side is very likely to be expensive, and has no side effects, then
it can generate code that evaluates a first, and then decides whether
or not to evaluate the left side.

I realize that this is a contrived example, but the bottom line is
that C was intended to be a *fast* language, and not a *safe* language.
Why nail the compiler's foot to the floor if you don't have to.

(When I first heard about the C language, it was described to me
as a substitute for assembly language.  I think that's the proper
attitude to take when deciding between fast and pedantic.)

-- 
	-Ed Falk, falk@despams.r.us.com
	http://thespamdiaries.blogspot.com/
0
Reply falk3260 (91) 2/8/2012 8:40:36 PM

On 2/7/2012 11:49 PM, Robert Wessel wrote:
> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
> <stephen@sprunk.org>  wrote:
[...]
>> No, they did evaluations in the order that made the most sense (i.e. had
>> the best performance) for their particular implementation--and
>> implementations vary.
>>
>> For instance, varargs is more straightforward to implement with
>> right-to-left evaluation of arguments, at least with a stack-based
>> calling convention.  Order of evaluation may not matter for
>> register-based calling conventions, but if an implementation uses both,
>> it makes sense to use the same order.
>
>
> Depends on which way your stack grows - with downward growth it's
> usually easiest to evaluate varargs right-to-left, but for an upwards
> growing stack left-to-right is usually easier.

I'm not sure why the direction in which the stack grows would matter.  The 
"top of the stack" is still the "top" whether it's the highest address or 
lowest currently used.

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/8/2012 8:42:03 PM

falk@rahul.net (Edward A. Falk) writes:
> In article <4f319955.234650417@text.giganews.com>,
> Richard Harter <cri@tiac.net> wrote:
>>Well, no, he isn't saying any such thing.  You just made it up.  The
>>fact that evaluation order in C is left to the compilers has very
>>little to do with optimization; it is a historical artifact that came
>>from endorsing existing practice when the ANSI standard was put
>>together.
>
> Perhaps, but it can still have a lot to do with optimization.
>
> Consider:
>
>   b = (sqrt(sin(x)*cos(x))) * a;
>
> If the compiler can guess that a is very likely to be zero, and that the
> left side is very likely to be expensive, and has no side effects, then
> it can generate code that evaluates a first, and then decides whether
> or not to evaluate the left side.
>
> I realize that this is a contrived example, but the bottom line is
> that C was intended to be a *fast* language, and not a *safe* language.
> Why nail the compiler's foot to the floor if you don't have to.

One problem with that contrived example is that the sqrt(), sin(), and
cos() functions can have the side effect of updating errno (if
math_errhandling & MATH_ERRNO is nonzero).

> (When I first heard about the C language, it was described to me
> as a substitute for assembly language.  I think that's the proper
> attitude to take when deciding between fast and pedantic.)

I don't disagree.  But there's a common misconception that C *is* an
assembly language (its' been called a "high-level assembler).  The key
difference is that an assembly language program specifies CPU
instructions, while a C program specifies behavior.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21467) 2/8/2012 11:00:12 PM

On 2012-02-07, Kenneth Brody <kenbrody@spamcop.net> wrote:
> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>> On 2012-02-07, Barry Schwarz<schwarzb@dqel.com>  wrote:
>>> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan<lujnan@gmail.com>
>>> wrote:
>>>
>>>> On Feb 6, 5:45 pm, bert<bert.hutchi...@btinternet.com>  wrote:
>>>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>>>> b = a = a++;
> [...]
>> I don't want diagnostics; I want strict left to right evaluation order
>> of operands and subexpressions that complete their side effects before
>> yielding a value.
>
> So, what you are really saying, is you want to eliminate most of C's 
> optimization abilities, by restricting the order in which the expression 
> *must* be evaluated, and side effects *must* be completed?

I do not believe that this is where "C's optimization abilities" come from
at all.

(Many of the optimization abilities of some early compilers from circa 1980
may have come from that, however.)

Do not forget the "as if" principle. I would want the above in the abstract
semantics, not in the actual semantics, of course.

Remember, C already has some constraints on evaluation order, like sequence
points between statements. Do you believe that sequential statements defeat
optimization?  Do you think that i++; i++ is slower than i += 2 because
it calls for i to be updated twice? (Assume non-volatile-qualified i.)
0
Reply kaz15 (1129) 2/8/2012 11:42:03 PM

On 2012-02-07, Richard Harter <cri@tiac.net> wrote:
> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
><kenbrody@spamcop.net> wrote:
>
>>On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>> On 2012-02-07, Barry Schwarz<schwarzb@dqel.com>  wrote:
>>>> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan<lujnan@gmail.com>
>>>> wrote:
>>>>
>>>>> On Feb 6, 5:45 pm, bert<bert.hutchi...@btinternet.com>  wrote:
>>>>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>>>>> b = a = a++;
>>[...]
>>> I don't want diagnostics; I want strict left to right evaluation order
>>> of operands and subexpressions that complete their side effects before
>>> yielding a value.
>>
>>So, what you are really saying, is you want to eliminate most of C's 
>>optimization abilities, by restricting the order in which the expression 
>>*must* be evaluated, and side effects *must* be completed?
>
> Well, no, he isn't saying any such thing.  You just made it up.  The
> fact that evaluation order in C is left to the compilers has very
> little to do with optimization; it is a historical artifact that came
> from endorsing existing practice when the ANSI standard was put
> together.  Existing practice then was that compiler writers could do
> evaluations in whatever they pleased and they did.

Exactly! Evaluation order could not have been standardized at the time
C was standardized for the first time, simply because it would have required
most compilers to change something. This is not the proper business of
a standard (to invent new stuff, that is). The proper business is to
identify the commonality in what is out there and codify it.

But, evidently, it IS now the business of C standardization to invent new crud.
So why don't they put a priority on tying loose ends left over from
the 1980's?

Before they started introducing crud like variable length arrays, they should
have revisited the behaviors that could not have been pinned down in 1989, and
tightened them up.

The problem is, I suspect, that some people have their egos invested in this
idiotic sequence point stuff. To throw it out the window would be a huge
backpedaling.  In C99 they just about nearly put out an new informative annex
which introduced a formal model of sequence points, which polished this turd
into a foot-deep shine.
0
Reply kaz15 (1129) 2/8/2012 11:49:47 PM

On 2012-02-07, Stephen Sprunk <stephen@sprunk.org> wrote:
> On 07-Feb-12 15:50, Richard Harter wrote:
>> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
>> <kenbrody@spamcop.net> wrote:
>>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>>> I don't want diagnostics; I want strict left to right evaluation order
>>>> of operands and subexpressions that complete their side effects before
>>>> yielding a value.
>>>
>>> So, what you are really saying, is you want to eliminate most of C's 
>>> optimization abilities, by restricting the order in which the expression 
>>> *must* be evaluated, and side effects *must* be completed?
>> 
>> Well, no, he isn't saying any such thing.  You just made it up.  The
>> fact that evaluation order in C is left to the compilers has very
>> little to do with optimization; it is a historical artifact that came
>> from endorsing existing practice when the ANSI standard was put
>> together.  Existing practice then was that compiler writers could do
>> evaluations in whatever they pleased and they did.
>
> No, they did evaluations in the order that made the most sense (i.e. had
> the best performance) for their particular implementation--and
> implementations vary.

Old compilers had hard-coded syntax-directed translation behaviors that were
convenient for the implementor. For instance a function call could be
handled as a single unit emitting some boiler-plate expansion.

> For instance, varargs is more straightforward to implement with
> right-to-left evaluation of arguments, at least with a stack-based
> calling convention.

You don't see that you're switching topics from "best performance" to
"straightforward to implement"?

The order matters only for arguments that have side effects.  Something like
f(a,b,"foo",x+y) can be evaluated in any order, even if the abstract semantics
calls for strict left to right.

If there are side effects, the order is required so that the same result
is reproduced no matter what. The code generated by the compiler from
a straightforward expression like f(i++, i++) should be no slower
than from an explicit refactoring like 
{ int temp0 = i++, temp1 = i++; f(temp0, temp1); }.

> Order of evaluation may not matter for
> register-based calling conventions, but if an implementation uses both,
> it makes sense to use the same order.

Speaking of stacks and registers, machine languages by and large well-defined
evaluation order, so it's laughable for a "higher level assembly" to screw this
up.

There have been some historic oddballs like early RISC processors that blindly
fetched instructions in sequence even though a branch is happening, requiring
the compiler or assembler to fill the delay slots sensibly or stick in NOPs.

It's the same theme theme like unspecified evaluation order in C: unsafe hack
for ease of implementation.
0
Reply kaz15 (1129) 2/9/2012 12:15:17 AM

On 2012-02-08, Stephen Sprunk <stephen@sprunk.org> wrote:
> On 07-Feb-12 22:49, Robert Wessel wrote:
>> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
>> <stephen@sprunk.org> wrote:
>>> On 07-Feb-12 15:50, Richard Harter wrote:
>>>> Well, no, he isn't saying any such thing.  You just made it up.  The
>>>> fact that evaluation order in C is left to the compilers has very
>>>> little to do with optimization; it is a historical artifact that came
>>>> from endorsing existing practice when the ANSI standard was put
>>>> together.  Existing practice then was that compiler writers could do
>>>> evaluations in whatever they pleased and they did.
>>>
>>> No, they did evaluations in the order that made the most sense (i.e. had
>>> the best performance) for their particular implementation--and
>>> implementations vary.
>>>
>>> For instance, varargs is more straightforward to implement with
>>> right-to-left evaluation of arguments, at least with a stack-based
>>> calling convention.  Order of evaluation may not matter for
>>> register-based calling conventions, but if an implementation uses both,
>>> it makes sense to use the same order.
>> 
>> Depends on which way your stack grows - with downward growth it's
>> usually easiest to evaluate varargs right-to-left, but for an upwards
>> growing stack left-to-right is usually easier.
>
> How would stack growth direction matter?  What matters for varargs is
> that the first argument is on the top of the stack, regardless of which
> way it grows.  If you push the arguments from right to left, the first
> argument ends up on top.  You _could_ evaluate the arguments from left
> to right, store them in registers or elsewhere in memory, and then push
> from right to left, but why go through that extra effort?

Or you could wake up and realize that the stack can be indexed like an array,
unless you're working with a target language that really has only push and
pop, with no other access to the stack. (Good luck implementing local
variables efficiently, etc).

You can allocate the space for N arguments, and then store valuews into
that stack space in whatever order is convenient, while obeying
the abstract evaluation order (in those situations where it potentially
makes a difference).
0
Reply kaz15 (1129) 2/9/2012 12:18:28 AM

On 2012-02-08, Kenneth Brody <kenbrody@spamcop.net> wrote:
> On 2/7/2012 4:50 PM, Richard Harter wrote:
>> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
>> <kenbrody@spamcop.net>  wrote:
>>
>>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>>> On 2012-02-07, Barry Schwarz<schwarzb@dqel.com>   wrote:
>>>>> On Mon, 6 Feb 2012 02:33:24 -0800 (PST), lujnan<lujnan@gmail.com>
>>>>> wrote:
>>>>>
>>>>>> On Feb 6, 5:45 pm, bert<bert.hutchi...@btinternet.com>   wrote:
>>>>>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>>>>>> b = a = a++;
>>> [...]
>>>> I don't want diagnostics; I want strict left to right evaluation order
>>>> of operands and subexpressions that complete their side effects before
>>>> yielding a value.
>>>
>>> So, what you are really saying, is you want to eliminate most of C's
>>> optimization abilities, by restricting the order in which the expression
>>> *must* be evaluated, and side effects *must* be completed?
>>
>> Well, no, he isn't saying any such thing.  You just made it up.  The
>> fact that evaluation order in C is left to the compilers has very
>> little to do with optimization; it is a historical artifact that came
>> from endorsing existing practice when the ANSI standard was put
>> together.  Existing practice then was that compiler writers could do
>> evaluations in whatever they pleased and they did.
>
> Well, not having access to the Standards committee, I can only speculate. 
> However, if evaluation order were the only thing at stake here, things would 
> have been left as "unspecified" rather than "undefined".

Last I looked, the order is in fact unspecified. But then what is undefined
is the multiple uses of the same object.

So for instance f(g(), h()); is not undefined behavior, but unspecified.
We don't know whether g is called first or h, but there are only two
possibilities.

In /practice/ there is no difference.

Unspecified, undefined: it all translates to hidden bugs in code that are not
caught by your regression test suite---even if that code has 100% coverage!

> In the 30+ years of programming in C, I don't believe I've ever had the need 
> to write code which depended on side-effects being completed in "the right 
> order" within a single statement.

I.e. you have written plenty of code with multiple side effects, but you're
sure that you didn't botch it.

> Whether that's because I know that 
> there's no such thing as "the right order", or because I never came across a 
> scenario where that might be useful, I cannot say, but I'm leaning towards 
> the latter.

I'm not so confident. After 30 years of coding, I'm still making coding
mistakes (even syntax!). I catch these with the help of the compiler, by
reviewing code, by test coverage, or sometimes with the help of other people.

These evaluation order issues fall into a category that is not caught
by tools, and not even by perfect test coverage, because a test case
could simply validate that the expected behavior is happening on the
given target machine and compiler.

I can't justify a belief that the mistakes I make are always, by good luck, in
categories that are caught by the compiler, or by test coverage.

Of course I haven't /knowingly/ stuffed multiple side effects into an
expression such that their order is critical to the correct outcome, for what
that is worth.
0
Reply kaz15 (1129) 2/9/2012 1:05:23 AM

On 2012-02-08, Edward A. Falk <falk@rahul.net> wrote:
> In article <4f319955.234650417@text.giganews.com>,
> Richard Harter <cri@tiac.net> wrote:
>>
>>Well, no, he isn't saying any such thing.  You just made it up.  The
>>fact that evaluation order in C is left to the compilers has very
>>little to do with optimization; it is a historical artifact that came
>>from endorsing existing practice when the ANSI standard was put
>>together.
>
> Perhaps, but it can still have a lot to do with optimization.
>
> Consider:
>
>   b = (sqrt(sin(x)*cos(x))) * a;
>
> If the compiler can guess that a is very likely to be zero, and that the
> left side is very likely to be expensive, and has no side effects, then
> it can generate code that evaluates a first, and then decides whether
> or not to evaluate the left side.

Since a is not volatile and those transcendental functions have no side
effects, this evaluation order would be allowed even if the evaluation order
for A * B is that A is evaluated first.

Why don't we change this to:

  b = sqrt(sin(x)*cos(x)) && a;

Or how about:

  b = sqrt(sin(x)*cos(x)), a;

Both && and , have ordering properties today.

If a is zero, do you believe that the trigonometry has to be evaluated?

> I realize that this is a contrived example, but the bottom line is
> that C was intended to be a *fast* language, and not a *safe* language.

Fast to implement, sure.

> Why nail the compiler's foot to the floor if you don't have to.

So that you don't shoot through yours.
0
Reply kaz15 (1129) 2/9/2012 1:10:29 AM

On 2012-02-07, Stephen Sprunk <stephen@sprunk.org> wrote:
> On 07-Feb-12 11:21, Kaz Kylheku wrote:
>> On 2012-02-07, James Kuyper <jameskuyper@verizon.net> wrote:
>>> I can think of two plausible defined
>>> behaviors for a=a++. One is equivalent to a++, so why bother with the
>>> "a="? The other is equivalent to a = a, so why bother writing anything
>>> at all?
>> 
>> One particular choice of behavior stands out: the simple, recursive rule:
>> 
>> - evaluate each subexpression completely, includiing all of its side effects,
>>   before evaluating the parent expression.
>> 
>> - if an expression has several subexpressions, evaluate them left to right.
>
> Nice of you to dictate that people using systems that more efficiently
> evaluate sub-expressions from right to left should suffer performance
> degradation of all code, even in the majority of cases where the code is

Proof?

> well-written and therefore the order doesn't actually matter, simply
> because it doesn't suit your sensibilities.

In the majority of cases, C code is not well-written. The history of C
programming at large is riddled with crashing applications and operating
systems, and exploitable security holes in online systems.

> If you /need/ to know that "foo(bar(), baz());" calls bar() before
> baz(), then just write "tmp=bar(); foo(tmp, baz());".  There is no need

Thanks for the clueful suggestion, but, see, what I need to know first is
WHERE this is hiding in a large code base.
0
Reply kaz15 (1129) 2/9/2012 1:27:16 AM

On Feb 8, 2:39=A0pm, Kenneth Brody <kenbr...@spamcop.net> wrote:
> On 2/7/2012 4:50 PM, Richard Harter wrote:
>
>
>
> > On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
> > <kenbr...@spamcop.net> =A0wrote:

[snip]

> Consider the fact that, in a "well behaved" program, the order of evaluat=
ion
> doesn't matter. =A0Consider, too, that an optimizer may change the order =
of
> evaluation to something more "efficient" on a given target platform.
>
> The truth of the matter is, is that when, precisely, a side effect most
> efficiently takes effect, is very platform-dependent, and can even vary f=
rom
> expression to expression on a given platform.
>

Is this anything more than received wisdom?  Does anyone have a
concrete example (read: generated machine code) showing *how*
rearranging evaluation order can make an operation more efficient?

I mean, I've parroted that line more than once, but I certainly can't
point to an example of where it makes a difference.
0
Reply jfbode1029 (227) 2/9/2012 1:41:44 AM

On 2012-02-08, Edward A. Falk <falk@rahul.net> wrote:
> In article <bf40ad26-3199-441e-a524-acf38177273f@og8g2000pbb.googlegroups.com>,
> lujnan  <lujnan@gmail.com> wrote:
>>Why C Standards Committee does not constrain this case.
>
> Because it's a dumb case.  You're not supposed to write that idiom,

You're only not "supposed" to write that only because the behavior isn't
standardized, so this is circular reasoning.

You were also not supposed to write this, prior to 1999:

  struct foo x = { .member = 42 };

nor this:

  { int x[var]; }

C programmers obviously sometimes do what they are not supposed to, otherwise
we would not need outfits like the Computer Emergency Response Team (CERT).

You may be a perfect C programmer who never does what isn't supposed
to be done, but that's a sample of one, and highly biased. 

I'm not such a programmer. All I can say is that I have never knowingly
broken the rules.  I do not buy arguments that "I have never needed that
behavior to be well-defined" or "I have never made such mistakes".

I do not buy the argument that the language should be unsafe, and programming
should be done only by those who can avoid stepping on the mines.  On a
project, it's good to have one such savant, but not the whole team.

Why should only programming language users be careful and responsible, but not
language designers?

> and pointless constraints are a bad thing in a system where performance
> is king.

The constraint only affects situations where expressions have interacting side
effects. All other code has the same meaning as without the constraints.
0
Reply kaz15 (1129) 2/9/2012 2:05:50 AM

On 02/08/2012 08:41 PM, John Bode wrote:
> Is this anything more than received wisdom?  Does anyone have a
> concrete example (read: generated machine code) showing *how*
> rearranging evaluation order can make an operation more efficient?

As a undergrad, I once had a summer job where I was responsible for
writing some hand-optimized assembler to replace two C subroutines that
had been found to be a bottleneck in a scientific calculation. I no
longer remember the concrete details you're asking for, but I do
remember the general strategies I used, and they all depended upon
rearranging the evaluation order.

On the machine I was writing for, there was one component that could
handle either a division or a sqrt() operation in parallel with
multiplications and additions. The main loop required one division,
followed by a sqrt(), followed by another division. Division and sqrt()
both took much longer than either a multiplication or an addition, so
one of the first things I did was rearrange evaluation so the division
started as early as possible, and was immediately followed by the
sqrt(), which was then followed by the second division, and I rearranged
things so that as many multiplications and additions as possible were
done between the start of the division and the completion of the sqrt().

Another key aspect of this machine was a component that could carry out
the register-based equivalent of fma() in three clock cycles, and could
be working on three different fma() operations at the same time, if they
were each started on a different clock cycle. Because the subroutine was
carrying out matrix multiplications, I could easily arrange to keep that
component busy almost full time, but doing so required rearranging the
order of evaluation extensively.

Finally, one of the key things I could do which the compiler was not
able to do, was to treat three different registers as the elements of a
3-component array. This helped to drastically reduce the number of slow
load and store operations, but it meant that a naive implementation of
the subroutine would have required three times as many registers as were
actually available. I dealt with this by rearranging the order of
evaluation so that the each register could be used to represent the
value of several different variables during the course of the
subroutine, by making sure that the periods of time during which the
register represented each variable didn't overlap. IIRC, if there had
been even a single additional register, I could have completely avoided
using RAM for any of the intermediate steps; as it was, I think there
was only one load and one store per pass through the main loop.

It was my first and last project writing in that assembly language. I
documented as accurately as I could precisely how I had designed it, but
I'm sure it was almost completely unmaintainable. My supervisor expected
me to spend the entire summer on it. I completed it in a couple of
weeks, and sped up the subroutine by a factor of 3.5, which disappointed
me - I'd been expecting a factor of 5. But the relevant subroutine was
going to be keeping hundreds of processors busy with a nearly 100% duty
cycle for several years, so that speed-up easily paid for the cost of my
salary. And most of it would have been impossible if I'd not been free
to rearrange the order of evaluation.

All of my rearrangements conformed to the as-if rule, however, so I'm
not sure they're directly relevant to this discussion. The real issue is
whether declaring certain kinds of behavior undefined makes it easier to
optimize code by mechanisms that would violate the as-if rule if the
behavior were defined. I believe this is the case, but I don't have any
anecdotes that demonstrate that fact.
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/9/2012 3:25:10 AM

On Wed, 08 Feb 2012 14:08:40 -0600, Stephen Sprunk
<stephen@sprunk.org> wrote:

>On 07-Feb-12 22:49, Robert Wessel wrote:
>> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
>> <stephen@sprunk.org> wrote:
>>> On 07-Feb-12 15:50, Richard Harter wrote:
>>>> Well, no, he isn't saying any such thing.  You just made it up.  The
>>>> fact that evaluation order in C is left to the compilers has very
>>>> little to do with optimization; it is a historical artifact that came
>>>> from endorsing existing practice when the ANSI standard was put
>>>> together.  Existing practice then was that compiler writers could do
>>>> evaluations in whatever they pleased and they did.
>>>
>>> No, they did evaluations in the order that made the most sense (i.e. had
>>> the best performance) for their particular implementation--and
>>> implementations vary.
>>>
>>> For instance, varargs is more straightforward to implement with
>>> right-to-left evaluation of arguments, at least with a stack-based
>>> calling convention.  Order of evaluation may not matter for
>>> register-based calling conventions, but if an implementation uses both,
>>> it makes sense to use the same order.
>> 
>> Depends on which way your stack grows - with downward growth it's
>> usually easiest to evaluate varargs right-to-left, but for an upwards
>> growing stack left-to-right is usually easier.
>
>How would stack growth direction matter?  What matters for varargs is
>that the first argument is on the top of the stack, regardless of which
>way it grows.  If you push the arguments from right to left, the first
>argument ends up on top.  You _could_ evaluate the arguments from left
>to right, store them in registers or elsewhere in memory, and then push
>from right to left, but why go through that extra effort?
>
>(This, of course, assumes a stack-based calling convention for varargs
>calls, as all of the ABIs I'm familiar with dictate, and possibly for
>other calls.)


So long as you can conveniently reference successive arguments with
increasing negative offsets, which is usually the case.  The
implementation I was thinking of supports only positive offsets
(obviously you can synthesize negative offsets), and the convention
was to pass a pointer to the first argument.  Of course that's not
really dependent on stack growth direction, you'd have the same issue
(in reverse) with a downwards growing stack on a machine that
perversely supported only negative offsets.
0
Reply robertwessel2 (1339) 2/9/2012 4:35:30 AM

On 06.02.2012 10:45, bert wrote:
> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>> b = a = a++;
> 
> The question is posted in this group many times. 
> Read the FAQ.  The result is undefined - that is, 
> it is DEFINED to be undefined.  That means it is 
> okay for the result to be different in different 
> compilers, and it is even okay for it to be 
> different in the same compiler in different 
> places or at different times.

On a related note, what about the following:

static int foo;
static int bar(void)
{
    return foo++;
}

int main(void)
{
    return foo++ - bar();
}

The standard sticks a sequence point between the evaluation of a
function call's arguments but not after its return. bar() is not
guarenteed to be called before or after evaluation of foo++, so bar()
can have different results. So does the above program exhibit UB?

Because if it does, that means that no-one should use function calls in
compound expressions. Unless the function called is pure or there's only
one function call which is compounded only with local variables (i.e.
variables with a scope smaller than file scope).

Ciao,
Markus
0
Reply nullplan (53) 2/9/2012 8:28:16 AM

On 2012-02-09, Markus Wichmann <nullplan@gmx.net> wrote:
> On 06.02.2012 10:45, bert wrote:
>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>> b = a = a++;
>> 
>> The question is posted in this group many times. 
>> Read the FAQ.  The result is undefined - that is, 
>> it is DEFINED to be undefined.  That means it is 
>> okay for the result to be different in different 
>> compilers, and it is even okay for it to be 
>> different in the same compiler in different 
>> places or at different times.
>
> On a related note, what about the following:
>
> static int foo;
> static int bar(void)
> {
>     return foo++;
> }
>
> int main(void)
> {
>     return foo++ - bar();
> }

I would have to say that this is unspecified behavior, not undefined.
There are these possibilities.

Scenario 1:

The processing of the foo++ in main takes place like this. First foo
has to be accessed, and then the new value stored. So the call to bar can occur
in three abstract places: 1) before foo is accessed, 2) after it is accessed but
before the new value is stored, or 3) after the new value is stored.

Case 1 is similar to this:

  int temp = bar();
  return foo++ - temp; /* foo becomes 2, 1 returned */

Case 2 is similar to this:

  int temp0 = foo, temp1 = bar(); /* 0, 0 */
  return foo = temp0 + 1, temp0; /* foo becomes 1, 0 returned */

Case 3:

  int temp = foo++; /* 0, foo becomes 1 */
  return temp - bar(); /* foo becomes 2, -1 returned */

Notice the symmetry between case 1 and 3.  2 is the most complex; we need
to expose its semantics using two temporary values. This is because the call to
bar() is interposed into the evaluation of foo++.

Scenario 2:

foo++ works by accessing the value, adding 1 to it, storing the new value,
accessing the value again and then subtracting 1 to produce the resulting
value. If foo is not volatile, this is allowed because the accesses are not
visible behavior.  Now bar() can be called first, after the value is accessed,
after it is stored, then after it is accessed again. Here you have four cases
that can be worked out similarly to Scenario 1.
0
Reply kaz15 (1129) 2/9/2012 10:21:36 AM

On 2012-02-09, Kaz Kylheku <kaz@kylheku.com> wrote:
> I would have to say that this is unspecified behavior, not undefined.
> There are these possibilities.

By the way I did consider the possibility that the access to foo may not be
atomic. I don't think that a function call can be issued in the middle of an
access to a global, because it seems that the sequence point isn't honored in
that case, but I will chew on that one.

The main thing about this sequence point crap is that you can look smart while
discussing it, even if the conclusions are vague.
0
Reply kaz15 (1129) 2/9/2012 11:38:00 AM

On 2/8/2012 7:15 PM, Kaz Kylheku wrote:
> On 2012-02-07, Stephen Sprunk<stephen@sprunk.org>  wrote:
[...]
>> For instance, varargs is more straightforward to implement with
>> right-to-left evaluation of arguments, at least with a stack-based
>> calling convention.
>
> You don't see that you're switching topics from "best performance" to
> "straightforward to implement"?
>
> The order matters only for arguments that have side effects.  Something like
> f(a,b,"foo",x+y) can be evaluated in any order, even if the abstract semantics
> calls for strict left to right.
>
> If there are side effects, the order is required so that the same result
> is reproduced no matter what.

.... unless the code invokes UB.

And, what about "unspecified" and/or "implementation-defined"?

There is no guarantee that this will give the same result "no matter what":

     foobar(printf("foo"),printf("bar"));

> The code generated by the compiler from
> a straightforward expression like f(i++, i++) should be no slower
> than from an explicit refactoring like
> { int temp0 = i++, temp1 = i++; f(temp0, temp1); }.

But the Standard makes no guarantees that your sample is the "as-if" that 
must result.  It could just as validly be "as if"

     int temp = i;
     i += 2;
     f(temp,temp);

(In fact, given that the code is UB, "anything" is "legal", though there are 
limited "likely, except for the DS-9000" results.)

[...]

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/9/2012 5:49:58 PM

On 2/8/2012 7:18 PM, Kaz Kylheku wrote:
[...]
> Or you could wake up and realize that the stack can be indexed like an array,
> unless you're working with a target language that really has only push and
> pop, with no other access to the stack. (Good luck implementing local
> variables efficiently, etc).
>
> You can allocate the space for N arguments, and then store valuews into
> that stack space in whatever order is convenient, while obeying
> the abstract evaluation order (in those situations where it potentially
> makes a difference).

Once again, conformity versus efficiency.

The efficient:

     PUSH C
     PUSH B
     PUSH A

versus the conforming:

     SUB  SP,12
     STOR [SP],A
     STOR [SP+4],B
     STOR [SP+8],C

(Note, of course, that it is possible that there are machines on which the 
calculated-store is faster than push, and may improve speed even with the 
added stack-adjust, in which case it is certainly free to generate such 
code.  The problem comes when you mandate it.)

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/9/2012 6:06:09 PM

On 2/8/2012 8:41 PM, John Bode wrote:
> On Feb 8, 2:39 pm, Kenneth Brody<kenbr...@spamcop.net>  wrote:
[...]
>> The truth of the matter is, is that when, precisely, a side effect most
>> efficiently takes effect, is very platform-dependent, and can even vary from
>> expression to expression on a given platform.
>>
>
> Is this anything more than received wisdom?  Does anyone have a
> concrete example (read: generated machine code) showing *how*
> rearranging evaluation order can make an operation more efficient?
>
> I mean, I've parroted that line more than once, but I certainly can't
> point to an example of where it makes a difference.

foo(a++,a++);

On my system, this code is generated:

         mov     eax, DWORD PTR _a
         push    eax
         push    eax
         add     eax, 2
         mov     DWORD PTR _a, eax
         call    _foo
         add     esp, 8

By delaying the post-increment, the code is more efficient than requiring 
two separate increments.

In fact, the above line of code, when compile w/o any optimization, does the 
"use the stack like an array" as someone else suggested to handle the 
"strict left-to-right evaluation":

tv68 = -8
tv65 = -4
[...]
         mov     ebp, esp
         sub     esp, 8
         mov     eax, DWORD PTR _a
         mov     DWORD PTR tv65[ebp], eax
         mov     ecx, DWORD PTR _a
         mov     DWORD PTR tv68[ebp], ecx
         mov     edx, DWORD PTR _a
         add     edx, 1
         mov     DWORD PTR _a, edx
         mov     eax, DWORD PTR _a
         add     eax, 1
         mov     DWORD PTR _a, eax
         mov     ecx, DWORD PTR tv65[ebp]
         push    ecx
         mov     edx, DWORD PTR tv68[ebp]
         push    edx
         call    _foo
         add     esp, 8

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/9/2012 6:15:29 PM

On 2/9/2012 3:28 AM, Markus Wichmann wrote:
[...]
> On a related note, what about the following:
>
> static int foo;
> static int bar(void)
> {
>      return foo++;
> }
>
> int main(void)
> {
>      return foo++ - bar();
> }
>
> The standard sticks a sequence point between the evaluation of a
> function call's arguments but not after its return.

But there _is_ a sequence point as part of the return statement itself.

> bar() is not
> guarenteed to be called before or after evaluation of foo++, so bar()
> can have different results. So does the above program exhibit UB?

I believe it's unspecified, due to the unspecified nature of order of 
evaluation.  There is guaranteed to be a sequence between the two 
increments, regardless of evaluation order.

> Because if it does, that means that no-one should use function calls in
> compound expressions. Unless the function called is pure or there's only
> one function call which is compounded only with local variables (i.e.
> variables with a scope smaller than file scope).


-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/9/2012 6:22:03 PM

On 09-Feb-12 12:06, Kenneth Brody wrote:
> On 2/8/2012 7:18 PM, Kaz Kylheku wrote:
>> Or you could wake up and realize that the stack can be indexed like
>> an array, unless you're working with a target language that really
>> has only push and pop, with no other access to the stack. (Good luck
>> implementing local variables efficiently, etc).
>>
>> You can allocate the space for N arguments, and then store valuews
>> into that stack space in whatever order is convenient, while obeying
>> the abstract evaluation order (in those situations where it
>> potentially makes a difference).
> 
> Once again, conformity versus efficiency.
> 
> The efficient:
> 
>     PUSH C
>     PUSH B
>     PUSH A
> 
> versus the conforming:
> 
>     SUB  SP,12
>     STOR [SP],A
>     STOR [SP+4],B
>     STOR [SP+8],C
> 
> (Note, of course, that it is possible that there are machines on which
> the calculated-store is faster than push, and may improve speed even
> with the added stack-adjust, in which case it is certainly free to
> generate such code.  The problem comes when you mandate it.)

Note that many modern CPUs can execute the latter version's three stores
in parallel, whereas the three simple pushes have an implicit dependency
on the stack pointer and may have to be executed serially, so the latter
is what compilers usually emit today.

However, that _wasn't_ the case back when all this stuff was being
decided: everything was serial, so the former version was faster as well
as smaller, both of which were a big deal back in the day.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/9/2012 7:58:26 PM

On 2012-02-09, Kenneth Brody <kenbrody@spamcop.net> wrote:
> There is no guarantee that this will give the same result "no matter what":
>
>      foobar(printf("foo"),printf("bar"));

No guarantee /now/. In this discussion thread, you are required to think
outside of the box, and keep a clean mental separation between the language as
it is, and the fantasy language in which evaluation orders are constrained
that is being discussed.

>> The code generated by the compiler from
>> a straightforward expression like f(i++, i++) should be no slower
>> than from an explicit refactoring like
>> { int temp0 = i++, temp1 = i++; f(temp0, temp1); }.
>
> But the Standard makes no guarantees that your sample is the "as-if" that 
> must result. 

The "compiler" above refers to one which ensures left to right,
bottom-up evaluation order. I.e. the behavior of 
{ int temp0 = i++, temp1 = i++; f(temp0, temp1); } could be obtained
simply by expressing f(i++, i++) with such a compiler.
0
Reply kaz15 (1129) 2/9/2012 11:51:23 PM

On 2012-02-09, Kenneth Brody <kenbrody@spamcop.net> wrote:
> On 2/8/2012 7:18 PM, Kaz Kylheku wrote:
> [...]
>> Or you could wake up and realize that the stack can be indexed like an array,
>> unless you're working with a target language that really has only push and
>> pop, with no other access to the stack. (Good luck implementing local
>> variables efficiently, etc).
>>
>> You can allocate the space for N arguments, and then store valuews into
>> that stack space in whatever order is convenient, while obeying
>> the abstract evaluation order (in those situations where it potentially
>> makes a difference).
>
> Once again, conformity versus efficiency.
>
> The efficient:
>
>      PUSH C
>      PUSH B
>      PUSH A

This is conforming, too if C, B and A don't have any side effects.
0
Reply kaz15 (1129) 2/9/2012 11:52:24 PM

On 2012-02-09, Kenneth Brody <kenbrody@spamcop.net> wrote:
> On 2/8/2012 8:41 PM, John Bode wrote:
>> On Feb 8, 2:39 pm, Kenneth Brody<kenbr...@spamcop.net>  wrote:
> [...]
>>> The truth of the matter is, is that when, precisely, a side effect most
>>> efficiently takes effect, is very platform-dependent, and can even vary from
>>> expression to expression on a given platform.
>>>
>>
>> Is this anything more than received wisdom?  Does anyone have a
>> concrete example (read: generated machine code) showing *how*
>> rearranging evaluation order can make an operation more efficient?
>>
>> I mean, I've parroted that line more than once, but I certainly can't
>> point to an example of where it makes a difference.
>
> foo(a++,a++);
>
> On my system, this code is generated:
>
>          mov     eax, DWORD PTR _a
>          push    eax
>          push    eax
>          add     eax, 2
>          mov     DWORD PTR _a, eax
>          call    _foo
>          add     esp, 8
>
> By delaying the post-increment, the code is more efficient than requiring 
> two separate increments.

Note that this is still allowed under strict left-right, bottom-up evaluation.

Because a is not volatile, the code does not require two actual increments.
That is merely the abstract semantics.

So this is really tangential to the debate. (Yes, rearranging computations is
important and crucial necessary for optimization.)
0
Reply kaz15 (1129) 2/9/2012 11:57:17 PM

On Feb 7, 9:31=A0am, Kaz Kylheku <k...@kylheku.com> wrote:
> Fact is, defined order is safe. Safety is the number one goal in engineer=
ing.

The entire argument of this thread can probably safely be skipped,
given that this assertion has been made.

In short, Kaz is wrong. There are always tradeoffs between safety,
cost, time to market, maintainability, extensibility, and so on.
Sometimes they do go hand in hand. Sometimes they clearly don't.
Different projects have different concerns, different weights on these
tradeoffs.

Nothing further need be said to safely dismiss this incredibly naive
view espoused by Kaz.
0
Reply joshuamaurice (576) 2/10/2012 1:50:42 AM

On Wed, 08 Feb 2012 14:29:05 -0600, Stephen Sprunk
<stephen@sprunk.org> wrote:

>On 08-Feb-12 08:47, Richard Harter wrote:
>> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
>> <stephen@sprunk.org> wrote:
>> 
>>> On 07-Feb-12 15:50, Richard Harter wrote:
>>>> On Tue, 07 Feb 2012 15:12:53 -0500, Kenneth Brody
>>>> <kenbrody@spamcop.net> wrote:
>>>>> On 2/7/2012 3:15 AM, Kaz Kylheku wrote:
>>>>>> I don't want diagnostics; I want strict left to right evaluation order
>>>>>> of operands and subexpressions that complete their side effects before
>>>>>> yielding a value.
>>>>>
>>>>> So, what you are really saying, is you want to eliminate most of C's 
>>>>> optimization abilities, by restricting the order in which the expression 
>>>>> *must* be evaluated, and side effects *must* be completed?
>>>>
>>>> Well, no, he isn't saying any such thing.  You just made it up.  The
>>>> fact that evaluation order in C is left to the compilers has very
>>>> little to do with optimization; it is a historical artifact that came
>>>> from endorsing existing practice when the ANSI standard was put
>>>> together.  Existing practice then was that compiler writers could do
>>>> evaluations in whatever they pleased and they did.
>>>
>>> No, they did evaluations in the order that made the most sense (i.e. had
>>> the best performance) for their particular implementation--and
>>> implementations vary.
>> 
>> You are not disagreeing with me.
>
>I disagree that they did "whatever they pleased"; they did what was best
>for their particular implementation, for various definitions of "best".

Then if they did whatever they thought was best then that was what
they pleased.  I'm not sure what you think "whatever they pleased"
means. 
>
>>> For instance, varargs is more straightforward to implement with
>>> right-to-left evaluation of arguments, at least with a stack-based
>>> calling convention.  Order of evaluation may not matter for
>>> register-based calling conventions, but if an implementation uses both,
>>> it makes sense to use the same order.
>> 
>> Well, yes, I know that.  However what you are talking about is a minor
>> micro-optimization at most.
>
>It doesn't seem so minor, particularly for platforms where _every_ call
>uses a stack-based calling convention.

Whoa.  The claim was about the cost of implementing varargs, something
only used in a rather small number of cases.  For that matter, at the
time varargs was not standardized.  Optimizing processing varargs was
and is a micro-optimization, then and now.   

>Remember, we're talking about
>long ago when compilers were rather dumb and most popular architectures
>were register-starved.

Granted.  And it is also true that the generated code in the bodies of
functions also suffered both because the architectures were limited
and, quite bluntly, the quality of most implementations were limited.
Furthermore evaluating function arguments right to left rather than
left to right is an almost imperceptible micro-optimization when it is
an optimization at all.  

>That is the environment that ANSI was faced
>with, and it would have been unreasonable to force the majority of
>implementations to suffer a performance penalty for the questionable
>benefit of left-to-right evaluation.

IMNSHO that performance penalty is much more fantasy than reality.  On
the other hand the cost of reworking all of those compilers was a very
real cost.  Quite reasonably, nobody wanted to pay that price.

On the other hand there is a real benefit when all behaviours are well
defined, when all code is either legal or illegal, and what the code
is supposed to do can be determined by inspection of the code.  The
qualility of C as a language would IMO be enhanced if most of these
"undefined behaviours" were compilation errors.






>
>> Historically the variations weren't a matter of performance - for the
>> most part the performance of the early compilers was less than
>> stellar.
>
>Of course; that was the state of the industry at the time.  All the more
>reason not to make things worse.
>
>> The various choices in calling sequence conventions and in
>> parsing order were a mixture of convenience and ad hoc decisions.  The
>> order variations were an unalterable part of the language by the time
>> it came to standardization.
>
>I think we can agree on this much: by the time ANSI looked at the
>matter, it was too late to "fix" many of the behaviors that ended up
>being called undefined, unspecified or implementation-defined because
>doing so would have broken a lot of code that implicitly depended on a
>particular implementation's pre-standard behavior.
>
>> In any event the idea that "most of C's optimization abilities" depend
>> upon not restricting evaluation order and side effect order is a wild
>> exaggeration.
>
>Optimization doesn't depend entirely on that particular gray area, but
>gray areas in general provide implementations leeway to make more
>aggressive optimizations because they lessen the impact of the "as if"
>rule.  Allowing the meaning of "a=a++;" to change isn't helpful in
>itself, but it may help the compiler optimize _something else_.
>
>Also, most of those gray areas aren't terribly useful in the first place
>and avoiding them generally results in clearer code anyway.  If _I_
>can't figure out what "a=a++;" is supposed to mean, without possibly
>resorting to the Standard, it's not important to me that the compiler
>knows either because I won't write it in the first place!  My primary
>audience is human, not machine.
>
>S
>
>-- 
>Stephen Sprunk         "God does not play dice."  --Albert Einstein
>CCIE #3723         "God is an inveterate gambler, and He throws the
>K5SSS        dice at every possible opportunity." --Stephen Hawking

0
Reply cri (1432) 2/10/2012 2:27:44 AM

On 2/8/2012 09:47, Richard Harter wrote:
>
> It was one thing to say that C is what it is, so suck it up and deal
> with it.  It is quite
>

Your post was truncated?
0
Reply sha0.miller (876) 2/10/2012 2:30:19 AM

On Wed, 08 Feb 2012 15:39:33 -0500, Kenneth Brody
<kenbrody@spamcop.net> wrote:


>In the 30+ years of programming in C, I don't believe I've ever had the need 
>to write code which depended on side-effects being completed in "the right 
>order" within a single statement.  Whether that's because I know that 
>there's no such thing as "the right order", or because I never came across a 
>scenario where that might be useful, I cannot say, but I'm leaning towards 
>the latter.

In my 30 odd years of programming in C I've come across cases where
the code only worked because of side-effects being completed in the
right order.  The problem is that I don't know what cases I've missed,
and, to be honest, I suspect you haven't either.

 
0
Reply cri (1432) 2/10/2012 2:32:23 AM

On Wed, 8 Feb 2012 20:40:36 +0000 (UTC), falk@rahul.net (Edward A.
Falk) wrote:

>In article <4f319955.234650417@text.giganews.com>,
>Richard Harter <cri@tiac.net> wrote:
[snip]
>
>I realize that this is a contrived example, but the bottom line is
>that C was intended to be a *fast* language, and not a *safe* language.
>Why nail the compiler's foot to the floor if you don't have to.

Well, no, C was intended as a convenient portable replacement for
assembly language in systems programming.  Safe and fast are not
opposites.


0
Reply cri (1432) 2/10/2012 2:40:53 AM

On Thu, 09 Feb 2012 21:30:19 -0500, Shao Miller
<sha0.miller@gmail.com> wrote:

>On 2/8/2012 09:47, Richard Harter wrote:
>>
>> It was one thing to say that C is what it is, so suck it up and deal
>> with it.  It is quite
>>
>
>Your post was truncated?

Apparently.  The text I sent was:

Granted there is no point in whining about C's lack of a well defined
evaluation.  C is what it is and "undefined" is pretty much carved in
stone.  But it has very little to do with optimization and a lot to do
with "that's the way things are; suck it up cupcake and live with it."



0
Reply cri (1432) 2/10/2012 2:48:10 AM

On 02/09/2012 09:27 PM, Richard Harter wrote:
> On Wed, 08 Feb 2012 14:29:05 -0600, Stephen Sprunk
> <stephen@sprunk.org> wrote:
> 
>> On 08-Feb-12 08:47, Richard Harter wrote:
>>> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
>>> <stephen@sprunk.org> wrote:
>>>
>>>> On 07-Feb-12 15:50, Richard Harter wrote:
....
>>>>> together.  Existing practice then was that compiler writers could do
>>>>> evaluations in whatever they pleased and they did.
>>>>
>>>> No, they did evaluations in the order that made the most sense (i.e. had
>>>> the best performance) for their particular implementation--and
>>>> implementations vary.
>>>
>>> You are not disagreeing with me.
>>
>> I disagree that they did "whatever they pleased"; they did what was best
>> for their particular implementation, for various definitions of "best".
> 
> Then if they did whatever they thought was best then that was what
> they pleased.  I'm not sure what you think "whatever they pleased"
> means.

"What they thought was best" is not, in general, the same as "What
pleased them most". For instance, for some implementors, it might have
pleased them most to insert warning messages that made fun of people
whose politics they disagreed with. But what they thought was best
probably didn't include losing that portion of their potential market
which would have been offended by such messages, nor that additional
share of their potential market that might have felt that such warning
messages showed insufficient professionalism.

I tried to come up with an example that more directly applies the
evaluation order of operands, but I had a hard time coming up with any
plausible examples where "pleasure" could be a significant issue.
Efficiency, ease of implementation, compatibility with other
implementations - I can see them all as being relevant, but I couldn't
figure out how to bring "pleasure" in to the mix for evaluation order
issues.
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/10/2012 4:10:46 AM

On 02/09/2012 09:32 PM, Richard Harter wrote:
> On Wed, 08 Feb 2012 15:39:33 -0500, Kenneth Brody
> <kenbrody@spamcop.net> wrote:
....
> In my 30 odd years of programming in C I've come across cases where

That sentence would work better with a quantifier of some kind before
the word "cases" - "many", "few", "a fair number", etc.

> the code only worked because of side-effects being completed in the
> right order.

You weren't the author, I hope? Can you provide an example?
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/10/2012 4:13:44 AM

On 02/09/2012 09:40 PM, Richard Harter wrote:
> On Wed, 8 Feb 2012 20:40:36 +0000 (UTC), falk@rahul.net (Edward A.
> Falk) wrote:
....
> Well, no, C was intended as a convenient portable replacement for
> assembly language in systems programming.  Safe and fast are not
> opposites.

Nor are they they same; as with any two characteristics that aren't
highly correlated, you can and often do have trade-offs between them.
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/10/2012 4:17:45 AM

On 2/8/2012 20:05, Kaz Kylheku wrote:
>
> These evaluation order issues fall into a category that is not caught
> by tools, and not even by perfect test coverage, because a test case
> could simply validate that the expected behavior is happening on the
> given target machine and compiler.
>

What is an example use case for having a defined evaluation order for 
function arguments?  I might have missed one or more.

Is it realistic that an implementation might have a thread of execution 
for each independent branch of evaluation, so that the evaluation order 
of some expressions might be simultaneous?
0
Reply sha0.miller (876) 2/10/2012 4:24:36 AM

=E5=9C=A8 2012=E5=B9=B42=E6=9C=889=E6=97=A5=E6=98=9F=E6=9C=9F=E5=9B=9BUTC+8=
=E4=B8=8A=E5=8D=889=E6=97=B610=E5=88=8629=E7=A7=92=EF=BC=8CKaz Kylheku=E5=
=86=99=E9=81=93=EF=BC=9A
> On 2012-02-08, Edward A. Falk <falk@rahul.net> wrote:
> > In article <4f319955.234650417@text.giganews.com>,
> > Richard Harter <cri@tiac.net> wrote:
> >>
> >>Well, no, he isn't saying any such thing.  You just made it up.  The
> >>fact that evaluation order in C is left to the compilers has very
> >>little to do with optimization; it is a historical artifact that came
> >>from endorsing existing practice when the ANSI standard was put
> >>together.
> >
> > Perhaps, but it can still have a lot to do with optimization.
> >
> > Consider:
> >
> >   b =3D (sqrt(sin(x)*cos(x))) * a;
> >
> > If the compiler can guess that a is very likely to be zero, and that th=
e
> > left side is very likely to be expensive, and has no side effects, then
> > it can generate code that evaluates a first, and then decides whether
> > or not to evaluate the left side.
>=20
> Since a is not volatile and those transcendental functions have no side
> effects, this evaluation order would be allowed even if the evaluation or=
der
> for A * B is that A is evaluated first.
>=20
> Why don't we change this to:
>=20
>   b =3D sqrt(sin(x)*cos(x)) && a;
>=20
> Or how about:
>=20
>   b =3D sqrt(sin(x)*cos(x)), a;
>=20
> Both && and , have ordering properties today.
>=20
> If a is zero, do you believe that the trigonometry has to be evaluated?
>=20

sqrt(sin(x)*cos(x))=3Dsqrt(sin(x*2)*0.5)

Even the sqrt function call can be simplified by a numerical=20
analysis, but this is not the language or compiler's job now.=20

Thus, it is time to distinguish different programming tools=20
for different jobs in different applications.=20

I don't believe that one computer language can solve all kinds of=20
tasks as a religeion proposed by some authors.=20

> > I realize that this is a contrived example, but the bottom line is
> > that C was intended to be a *fast* language, and not a *safe* language.
>=20
> Fast to implement, sure.
>=20
> > Why nail the compiler's foot to the floor if you don't have to.
>=20
> So that you don't shoot through yours.

0
Reply dihedral88888 (785) 2/10/2012 4:43:56 AM

On 2/9/2012 05:21, Kaz Kylheku wrote:
> On 2012-02-09, Markus Wichmann<nullplan@gmx.net>  wrote:
>> On 06.02.2012 10:45, bert wrote:
>>> On Monday, February 6, 2012 8:10:00 AM UTC, lujnan wrote:
>>>> b = a = a++;
>>>
>>> The question is posted in this group many times.
>>> Read the FAQ.  The result is undefined - that is,
>>> it is DEFINED to be undefined.  That means it is
>>> okay for the result to be different in different
>>> compilers, and it is even okay for it to be
>>> different in the same compiler in different
>>> places or at different times.
>>
>> On a related note, what about the following:
>>
>> static int foo;
>> static int bar(void)
>> {
>>      return foo++;
>> }
>>
>> int main(void)
>> {
>>      return foo++ - bar();
>> }
>
> I would have to say that this is unspecified behavior, not undefined.
> There are these possibilities.
>

In C11, the evaluation of 'foo++' is indeterminately sequenced relative 
to the call to 'bar'.  It is either before or after, but not a portion 
before and a portion after.[5.1.2.3p3, 6.5.2.2p10]

Then the behaviour doesn't appear to fall into 6.5p2, since it is no 
longer unsequenced given the consideration above.  So yes, it looks to 
be unspecified, in C11.
0
Reply sha0.miller (876) 2/10/2012 5:03:04 AM

On Thu, 9 Feb 2012 20:43:56 -0800 (PST), 88888 Dihedral
<dihedral88888@googlemail.com> wrote:

>? 2012?2?9????UTC+8??9?10?29??Kaz Kylheku???
>> On 2012-02-08, Edward A. Falk <falk@rahul.net> wrote:
>> > In article <4f319955.234650417@text.giganews.com>,
>> > Richard Harter <cri@tiac.net> wrote:
>> >>
>> >>Well, no, he isn't saying any such thing.  You just made it up.  The
>> >>fact that evaluation order in C is left to the compilers has very
>> >>little to do with optimization; it is a historical artifact that came
>> >>from endorsing existing practice when the ANSI standard was put
>> >>together.
>> >
>> > Perhaps, but it can still have a lot to do with optimization.
>> >
>> > Consider:
>> >
>> >   b = (sqrt(sin(x)*cos(x))) * a;
>> >
>> > If the compiler can guess that a is very likely to be zero, and that the
>> > left side is very likely to be expensive, and has no side effects, then
>> > it can generate code that evaluates a first, and then decides whether
>> > or not to evaluate the left side.
>> 
>> Since a is not volatile and those transcendental functions have no side
>> effects, this evaluation order would be allowed even if the evaluation order
>> for A * B is that A is evaluated first.
>> 
>> Why don't we change this to:
>> 
>>   b = sqrt(sin(x)*cos(x)) && a;
>> 
>> Or how about:
>> 
>>   b = sqrt(sin(x)*cos(x)), a;
>> 
>> Both && and , have ordering properties today.
>> 
>> If a is zero, do you believe that the trigonometry has to be evaluated?
>> 
>
>sqrt(sin(x)*cos(x))=sqrt(sin(x*2)*0.5)
>
>Even the sqrt function call can be simplified by a numerical 
>analysis, but this is not the language or compiler's job now. 
>
>Thus, it is time to distinguish different programming tools 
>for different jobs in different applications. 
>
>I don't believe that one computer language can solve all kinds of 
>tasks as a religeion proposed by some authors. 


For this particular case, why not?  I mean, we all expect a compiler
to (usually) evaluate a=b*2 as a=b+b.  Where do you think the limit
should be?  Why not expect a compiler to go so far as to evaluate that
as an appropriate range reduction followed by the very tractable
Taylor series* for sqrt(sin(x*2)*0.5)?  While I suspect most C users
would not get too excited about that, a bunch of HPC folks might - so
perhaps that optimization might be more likely in a Fortran compiler,
and putting a symbolic differentiation engine in the compiler might be
a bit extreme, but still, what's the limit?


*if we must:  x**(1/2) - (x**(5/2) / 3) + (x**(9/2) / 90) - (x**(13/2)
/ 378)...
0
Reply robertwessel2 (1339) 2/10/2012 5:36:55 AM

On Thu, 09 Feb 2012 23:10:46 -0500, James Kuyper
<jameskuyper@verizon.net> wrote:

>On 02/09/2012 09:27 PM, Richard Harter wrote:
>> On Wed, 08 Feb 2012 14:29:05 -0600, Stephen Sprunk
>> <stephen@sprunk.org> wrote:
>> 
>>> On 08-Feb-12 08:47, Richard Harter wrote:
>>>> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
>>>> <stephen@sprunk.org> wrote:
>>>>
>>>>> On 07-Feb-12 15:50, Richard Harter wrote:
>...
>>>>>> together.  Existing practice then was that compiler writers could do
>>>>>> evaluations in whatever they pleased and they did.
>>>>>
>>>>> No, they did evaluations in the order that made the most sense (i.e. had
>>>>> the best performance) for their particular implementation--and
>>>>> implementations vary.
>>>>
>>>> You are not disagreeing with me.
>>>
>>> I disagree that they did "whatever they pleased"; they did what was best
>>> for their particular implementation, for various definitions of "best".
>> 
>> Then if they did whatever they thought was best then that was what
>> they pleased.  I'm not sure what you think "whatever they pleased"
>> means.
>
>"What they thought was best" is not, in general, the same as "What
>pleased them most". 

Stop right there. "whatever they pleased" and "What pleased them most"
are two different things. 

[snip irrelevant remainder even though it is interesting]


0
Reply cri (1432) 2/10/2012 9:11:03 AM

Kaz Kylheku wrote:
> On 2012-02-09, Markus Wichmann wrote:
> > On a related note, what about the following:
> >
> > static int foo;
> > static int bar(void)
> > {
> >     return foo++;
> > }
> >
> > int main(void)
> > {
> >     return foo++ - bar();
> > }
> 
> I would have to say that this is unspecified behavior, not undefined.
> There are these possibilities.
> 
> Scenario 1:
> 
> The processing of the foo++ in main takes place like this. First foo
> has to be accessed, and then the new value stored. So the call to bar can occur
> in three abstract places: 1) before foo is accessed, 2) after it is accessed but
> before the new value is stored, or 3) after the new value is stored.
> 
> Case 1 is similar to this:
> 
>   int temp = bar();
>   return foo++ - temp; /* foo becomes 2, 1 returned */
> 
> Case 2 is similar to this:
> 
>   int temp0 = foo, temp1 = bar(); /* 0, 0 */
>   return foo = temp0 + 1, temp0; /* foo becomes 1, 0 returned */
> 
> Case 3:
> 
>   int temp = foo++; /* 0, foo becomes 1 */
>   return temp - bar(); /* foo becomes 2, -1 returned */
> 
> Notice the symmetry between case 1 and 3.  2 is the most complex; we need
> to expose its semantics using two temporary values. This is because the call to
> bar() is interposed into the evaluation of foo++.

I don't think your case 2 is allowed. If foo++ is evaluated before the 
call to bar(), then the sequence point before the call ensures that the 
side effect is complete before the call.
0
Reply prl1 (101) 2/10/2012 9:15:31 AM

On Thu, 09 Feb 2012 23:13:44 -0500, James Kuyper
<jameskuyper@verizon.net> wrote:

>On 02/09/2012 09:32 PM, Richard Harter wrote:
>> On Wed, 08 Feb 2012 15:39:33 -0500, Kenneth Brody
>> <kenbrody@spamcop.net> wrote:
>...
>> In my 30 odd years of programming in C I've come across cases where
>
>That sentence would work better with a quantifier of some kind before
>the word "cases" - "many", "few", "a fair number", etc.

Few works.  The problem is that in times of yore (pre-ansi) the rules
were different.  The ultimate authority about the legitimacy of C code
on a given machine was the compiler.  If your code had to run on
twenty different machines then you built and tested it on all of those
machines.  Any thing that didn't work, regardless of whether or not it
"should have" was a bug.  

>
>> the code only worked because of side-effects being completed in the
>> right order.
>
>You weren't the author, I hope? Can you provide an example?

At this remove there is only one case that I am certain of and that
only because it was discussed in comp.lang.c.  I will scrounge around
and see if I can find it.
0
Reply cri (1432) 2/10/2012 9:34:49 AM

On 2012-02-10, Richard Harter <cri@tiac.net> wrote:
> On Thu, 09 Feb 2012 21:30:19 -0500, Shao Miller
><sha0.miller@gmail.com> wrote:
>
>>On 2/8/2012 09:47, Richard Harter wrote:
>>>
>>> It was one thing to say that C is what it is, so suck it up and deal
>>> with it.  It is quite
>>>
>>
>>Your post was truncated?
>
> Apparently.  The text I sent was:
>
> Granted there is no point in whining about C's lack of a well defined
> evaluation.

Nobody is "whining". I made a well-considered criticism.

C would be a better language without gratuitous behaviors in the way abstract
expressions are put together.

> C is what it is and "undefined" is pretty much carved in
> stone. 

C is obviously not carved in stone, which is why there are so many C's to
choose from.  K&RC, C90, C99, C11 ...

Once upon a time it might have been "whining" to want better type checking
between function declarations and definitions.

> But it has very little to do with optimization and a lot to do
> with "that's the way things are; suck it up cupcake and live with it."

That is neither here nor there.

However, I might just implement this strict evaluation in GCC one of these days
as an option.  That would be a good start to actually get it done.

However, there is value in discussing the idea, too.
0
Reply kaz15 (1129) 2/10/2012 9:49:04 AM

On 02/10/2012 04:11 AM, Richard Harter wrote:
> On Thu, 09 Feb 2012 23:10:46 -0500, James Kuyper
> <jameskuyper@verizon.net> wrote:
....
>> "What they thought was best" is not, in general, the same as "What
>> pleased them most". 
> 
> Stop right there. "whatever they pleased" and "What pleased them most"
> are two different things. 

True - and yet, if you took every occurrence of "what pleased them
most", or variations of the same, from my message, and replace it with a
corresponding variation on "whatever they pleased", the message would
remain equally true.
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/10/2012 12:26:17 PM

On 02/10/2012 04:34 AM, Richard Harter wrote:
> On Thu, 09 Feb 2012 23:13:44 -0500, James Kuyper
> <jameskuyper@verizon.net> wrote:
> 
>> On 02/09/2012 09:32 PM, Richard Harter wrote:
>>> On Wed, 08 Feb 2012 15:39:33 -0500, Kenneth Brody
>>> <kenbrody@spamcop.net> wrote:
>> ...
>>> In my 30 odd years of programming in C I've come across cases where
>>
>> That sentence would work better with a quantifier of some kind before
>> the word "cases" - "many", "few", "a fair number", etc.
> 
> Few works.  The problem is that in times of yore (pre-ansi) the rules
> were different.  The ultimate authority about the legitimacy of C code
> on a given machine was the compiler.  If your code had to run on
> twenty different machines then you built and tested it on all of those
> machines.  Any thing that didn't work, regardless of whether or not it
> "should have" was a bug.

Well, yes - pre-ANSI was a different issue. In the post-ANSI C world,
however, any code that relied upon the order in which side-effects
occurred, when that order was unspecified by the C standard, was
defective. In general, I'm a big believer in the concept that not all
code needs to be portable - but this particular kind of non-portability
doesn't seem to have any value. You can always re-write the code to
guarantee the desired order of side-effects, and the result of doing so
is usually code that would still be clearer than the original even if
the standard were changed to specify the order of the side effects in
the original.
-- 
James Kuyper
0
Reply jameskuyper (5151) 2/10/2012 12:32:43 PM

James Kuyper <jameskuyper@verizon.net> writes:

> On 02/10/2012 04:11 AM, Richard Harter wrote:
>> On Thu, 09 Feb 2012 23:10:46 -0500, James Kuyper
>> <jameskuyper@verizon.net> wrote:
> ...
>>> "What they thought was best" is not, in general, the same as "What
>>> pleased them most". 
>> 
>> Stop right there. "whatever they pleased" and "What pleased them most"
>> are two different things. 
>
> True - and yet, if you took every occurrence of "what pleased them
> most", or variations of the same, from my message, and replace it with a
> corresponding variation on "whatever they pleased", the message would
> remain equally true.

I can't make that work.  Your usage emphasises (explicitly) the idea of
pleasure being involved, and that is surely the difference Richard
Harter is pointing out.  "What pleased them most" is about pleasure and
gratification, but "whatever they please" is about having "the will or
desire; to have the inclination or disposition; to think proper; to
choose" (though having pleasure in the result is not excluded, of
course).

-- 
Ben.
0
Reply ben.usenet (6515) 2/10/2012 1:12:36 PM

Am 02/10/2012 05:24 AM, schrieb Shao Miller:
> Is it realistic that an implementation might have a thread of execution
> for each independent branch of evaluation, so that the evaluation order
> of some expressions might be simultaneous?

thread of execution in a broad sense, certainly, such as done for
pipelining processors with out-of-order execution

compilers do reordering of statements all the time, and not imposing a
sequence point between two evaluations is giving the necessary slackness
to the compiler for doing so.

Jens
0
Reply Jens.Gustedt1 (231) 2/10/2012 3:58:11 PM

On 02/10/2012 08:12 AM, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
> 
>> On 02/10/2012 04:11 AM, Richard Harter wrote:
>>> On Thu, 09 Feb 2012 23:10:46 -0500, James Kuyper
>>> <jameskuyper@verizon.net> wrote:
>> ...
>>>> "What they thought was best" is not, in general, the same as "What
>>>> pleased them most". 
>>>
>>> Stop right there. "whatever they pleased" and "What pleased them most"
>>> are two different things. 
>>
>> True - and yet, if you took every occurrence of "what pleased them
>> most", or variations of the same, from my message, and replace it with a
>> corresponding variation on "whatever they pleased", the message would
>> remain equally true.
> 
> I can't make that work.  Your usage emphasises (explicitly) the idea of
> pleasure being involved, and that is surely the difference Richard
> Harter is pointing out.  "What pleased them most" is about pleasure and
> gratification, but "whatever they please" is about having "the will or
> desire; to have the inclination or disposition; to think proper; to
> choose" (though having pleasure in the result is not excluded, of
> course).

I think that any interpretation of "whatever they please" that doesn't
connect to the concept of pleasure is somewhat odd, but it's not really
a problem for what I was saying. The key point of what I wrote was that
"whatever they please" is different from "what they thought was best";
the details of how they differ are less important than the fact of a
difference.

It's not exactly an unusual thing for people to have the will, desire,
inclination or disposition to do something other than what they think is
best.  It's not even usual for people to actually choose to do something
other than what they think best.
0
Reply jameskuyper (5151) 2/10/2012 4:07:44 PM

On 2/9/2012 6:57 PM, Kaz Kylheku wrote:
> On 2012-02-09, Kenneth Brody<kenbrody@spamcop.net>  wrote:
>> On 2/8/2012 8:41 PM, John Bode wrote:
>>> On Feb 8, 2:39 pm, Kenneth Brody<kenbr...@spamcop.net>   wrote:
>> [...]
>>>> The truth of the matter is, is that when, precisely, a side effect most
>>>> efficiently takes effect, is very platform-dependent, and can even vary from
>>>> expression to expression on a given platform.
>>>>
>>>
>>> Is this anything more than received wisdom?  Does anyone have a
>>> concrete example (read: generated machine code) showing *how*
>>> rearranging evaluation order can make an operation more efficient?
>>>
>>> I mean, I've parroted that line more than once, but I certainly can't
>>> point to an example of where it makes a difference.
>>
>> foo(a++,a++);
>>
>> On my system, this code is generated:
>>
>>           mov     eax, DWORD PTR _a
>>           push    eax
>>           push    eax
>>           add     eax, 2
>>           mov     DWORD PTR _a, eax
>>           call    _foo
>>           add     esp, 8
>>
>> By delaying the post-increment, the code is more efficient than requiring
>> two separate increments.
>
> Note that this is still allowed under strict left-right, bottom-up evaluation.

Not according to the "and all side-effects must take place immediately" part 
of the argument.  In that case, the second parameter *must* be one more than 
the original value of a.

> Because a is not volatile, the code does not require two actual increments.
> That is merely the abstract semantics.

True, the as-if rule can be satisfied by the single "add 2" operation, but 
the "side-effects must take place immediately" cannot.

And, making "a" volatile gives this code:

         mov     eax, DWORD PTR _a
         mov     ecx, DWORD PTR _a
         mov     edx, 1
         add     DWORD PTR _a, edx
         add     DWORD PTR _a, edx
         push    eax
         push    ecx
         call    _foo
         add     esp, 8

Now, the two increments are done separately, but the code was still 
rearranged so that they still take place after grabbing the original values 
of "a".  Whether this is faster than moving one of the adds between the two 
reads of "a", I don't know, nor do I have the time or resources to investigate.

> So this is really tangential to the debate. (Yes, rearranging computations is
> important and crucial necessary for optimization.)

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/10/2012 4:15:14 PM

On Fri, 10 Feb 2012 07:26:17 -0500, James Kuyper
<jameskuyper@verizon.net> wrote:

>On 02/10/2012 04:11 AM, Richard Harter wrote:
>> On Thu, 09 Feb 2012 23:10:46 -0500, James Kuyper
>> <jameskuyper@verizon.net> wrote:
>...
>>> "What they thought was best" is not, in general, the same as "What
>>> pleased them most". 
>> 
>> Stop right there. "whatever they pleased" and "What pleased them most"
>> are two different things. 
>
>True - and yet, if you took every occurrence of "what pleased them
>most", or variations of the same, from my message, and replace it with a
>corresponding variation on "whatever they pleased", the message would
>remain equally true.

I agree with Ben; it doesn't work, though you might give it a try.  If
you do, start with "whatever they chanced to do" or something similar.

That said, the point you made is quite valid. What I was getting at,
though, is that without the constraint of a standard or something
implementation choices have an element of caprice and arbitrariness.  

0
Reply cri (1432) 2/10/2012 4:27:52 PM

On 2/10/2012 4:34 AM, Richard Harter wrote:
> On Thu, 09 Feb 2012 23:13:44 -0500, James Kuyper
> <jameskuyper@verizon.net>  wrote:
>
>> On 02/09/2012 09:32 PM, Richard Harter wrote:
>>> On Wed, 08 Feb 2012 15:39:33 -0500, Kenneth Brody
>>> <kenbrody@spamcop.net>  wrote:
>> ...
>>> In my 30 odd years of programming in C I've come across cases where
>>
>> That sentence would work better with a quantifier of some kind before
>> the word "cases" - "many", "few", "a fair number", etc.
>
> Few works.  The problem is that in times of yore (pre-ansi) the rules
> were different.  The ultimate authority about the legitimacy of C code
> on a given machine was the compiler.  If your code had to run on
> twenty different machines then you built and tested it on all of those
> machines.  Any thing that didn't work, regardless of whether or not it
> "should have" was a bug.
[...]

Pre-ansi days were certainly "fun" (FSVO).

Of course, given that the first major C project I worked on needed to run on 
both a 68000-based (32-bit big-endian) Unix system and an 8088-based (16-bit 
little-endian) MS-DOS system, I quickly learned how to handle such things.

I also learned (the hard way) not to use bit-fields on things written to 
disk, when we used a compiler which allocated bits in the opposite order. 
(Does the current Standard require a certain order?  ie: if you have 
"unsigned int foo:1", is it required to be either at the MSB or LSB?)

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/10/2012 4:35:58 PM

On 02/10/2012 11:27 AM, Richard Harter wrote:
> On Fri, 10 Feb 2012 07:26:17 -0500, James Kuyper
> <jameskuyper@verizon.net> wrote:
> 
>> On 02/10/2012 04:11 AM, Richard Harter wrote:
>>> On Thu, 09 Feb 2012 23:10:46 -0500, James Kuyper
>>> <jameskuyper@verizon.net> wrote:
>> ...
>>>> "What they thought was best" is not, in general, the same as "What
>>>> pleased them most". 
>>>
>>> Stop right there. "whatever they pleased" and "What pleased them most"
>>> are two different things. 
>>
>> True - and yet, if you took every occurrence of "what pleased them
>> most", or variations of the same, from my message, and replace it with a
>> corresponding variation on "whatever they pleased", the message would
>> remain equally true.
> 
> I agree with Ben; it doesn't work, though you might give it a try.  If
> you do, start with "whatever they chanced to do" or something similar.

Here's the re-write; it wasn't quite as simple as I implied, but it's
still trivial:

"What they thought was best" is not, in general, the same as "What
they pleased". For instance, some implementers might have been
pleased to insert warning messages that made fun of people
whose politics they disagreed with. But what they thought was best
probably didn't include losing that portion of their potential market
which would have been offended by such messages, nor that additional
share of their potential market that might have felt that such warning
messages showed insufficient professionalism.

I tried to come up with an example that more directly applies the
evaluation order of operands, but I had a hard time coming up with any
plausible examples where an implementor might have been pleased to do
something other than what they thought best.

> That said, the point you made is quite valid. What I was getting at,
> though, is that without the constraint of a standard or something
> implementation choices have an element of caprice and arbitrariness.  

I don't think that element is a big one. Implementors who pay attention
to the needs of their customers tend to find their choices significantly
constrained by those needs, and so long as they work within those
constraints, they tend to have more customers than those implementers
who let caprice and arbitrariness rule their designs.
0
Reply jameskuyper (5151) 2/10/2012 5:17:08 PM

On 02/10/2012 11:35 AM, Kenneth Brody wrote:
....
> Pre-ansi days were certainly "fun" (FSVO).
....
> I also learned (the hard way) not to use bit-fields on things written to 
> disk, when we used a compiler which allocated bits in the opposite order. 
> (Does the current Standard require a certain order?  ie: if you have 
> "unsigned int foo:1", is it required to be either at the MSB or LSB?)

No. It's not even required that different data types for the same
implementation use the bits in the same order on all types. Unsigned
char could use 1 ... 8, unsigned short could use 16 ... 1, unsigned
could use 1 32 2 31 ... 15 16, etc. I can't imagine any hardware being
built in a way that would make that a reasonable way to implement C, but
such an implementation could be conforming.


0
Reply jameskuyper (5151) 2/10/2012 5:23:17 PM

On 09-Feb-12 17:57, Kaz Kylheku wrote:
> On 2012-02-09, Kenneth Brody <kenbrody@spamcop.net> wrote:
>> On 2/8/2012 8:41 PM, John Bode wrote:
>>> On Feb 8, 2:39 pm, Kenneth Brody<kenbr...@spamcop.net>  wrote:
>> [...]
>>>> The truth of the matter is, is that when, precisely, a side effect most
>>>> efficiently takes effect, is very platform-dependent, and can even vary from
>>>> expression to expression on a given platform.
>>>>
>>>
>>> Is this anything more than received wisdom?  Does anyone have a
>>> concrete example (read: generated machine code) showing *how*
>>> rearranging evaluation order can make an operation more efficient?
>>>
>>> I mean, I've parroted that line more than once, but I certainly can't
>>> point to an example of where it makes a difference.
>>
>> foo(a++,a++);
>>
>> On my system, this code is generated:
>>
>>          mov     eax, DWORD PTR _a
>>          push    eax
>>          push    eax
>>          add     eax, 2
>>          mov     DWORD PTR _a, eax
>>          call    _foo
>>          add     esp, 8
>>
>> By delaying the post-increment, the code is more efficient than requiring 
>> two separate increments.
> 
> Note that this is still allowed under strict left-right, bottom-up evaluation.

My interpretation of "strict left-to-right" evaluation is equivalent to
this:

tmp1 = a++;
tmp2 = a++;
foo(tmp1, tmp2);

So, this would be a valid optimization:

foo(a, a+1);
a+=2;

In contrast, the above asm has the side effect of the first "a++"
expression occurring _after_ the evaluation of the second expressions,
like this:

foo(a, a);
a+=2;

> Because a is not volatile, the code does not require two actual increments.
> That is merely the abstract semantics.

Of course.  However, when exactly each postincrement happens _in the
virtual machine_ does affect the value of the second argument to foo().

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/10/2012 5:53:08 PM

On 10-Feb-12 10:15, Kenneth Brody wrote:
> On 2/9/2012 6:57 PM, Kaz Kylheku wrote:
>> Because a is not volatile, the code does not require two actual
>> increments.
>> That is merely the abstract semantics.
> 
> True, the as-if rule can be satisfied by the single "add 2" operation,
> but the "side-effects must take place immediately" cannot.
> 
> And, making "a" volatile gives this code:
> 
>         mov     eax, DWORD PTR _a
>         mov     ecx, DWORD PTR _a
>         mov     edx, 1
>         add     DWORD PTR _a, edx
>         add     DWORD PTR _a, edx
>         push    eax
>         push    ecx
>         call    _foo
>         add     esp, 8
> 
> Now, the two increments are done separately, but the code was still
> rearranged so that they still take place after grabbing the original
> values of "a".  Whether this is faster than moving one of the adds
> between the two reads of "a", I don't know, nor do I have the time or
> resources to investigate.

"Faster" is perhaps irrelevant in this case because _the result is
different_, which shows exactly why invoking undefined behavior can be
such a problem.

The above asm does this:

tmp1 = a;
tmp2 = a;
a = tmp1 + 1;
a = tmp2 + 1;
foo(tmp1, tmp2);

Note that, despite two increments, the final value of a is only _one_
greater than its initial value.

This would not be a valid optimization if there were a sequence point
between arguments, as proposed.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/10/2012 5:58:28 PM

On 07-Feb-12 16:00, James Kuyper wrote:
> On 02/07/2012 04:19 PM, Stephen Sprunk wrote:
>> On 07-Feb-12 05:07, Nick Keighley wrote:
>>>     the statement is undefined
>>>     =>
>>>     compilers are permitted to produce different answers
>>>    (or trap or crash or anything else weird the compiler writer feels
>>> like)
>>
>> Compilers existed prior to the standard, so their divergent behavior
>> could not possibly be blamed on a non-existent standard allowing it.
> 
> True; but the fact that different current compilers give different
> results cannot be used to validly infer that the behavior is undefined.
> The behavior could be implementation-defined, or simply unspecified, or
> one of the compilers you're comparing could be non-conforming.

True, divergent behavior could have been classified several different
ways by the Standard.  I was merely pointing out that divergent behavior
caused such classification, rather than the classification causing such
divergent behavior as you seemed to be saying.

> Incidentally, it was made explicitly clear that "existing code is
> important; existing implementations are not". I would presume that was
> based upon the fact that, for any reasonably successful implementation
> of C, the amount of code written for use on that implementation greatly
> outweighed the amount of code required to implement it.

True.  However, the importance of that statement comes from the fact
that a significant amount of "existing code" had come to _depend_ on the
behavior of a particular implementation.  Therefore, such behavior would
need to remain valid for that implementation.  The insides of a compiler
might need to change, and new features could be tacked on, but it
couldn't be done in a way that forced existing code to stop working, no
matter how ugly the code might be.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/10/2012 6:05:24 PM

On 10-Feb-12 11:17, James Kuyper wrote:
> I tried to come up with an example that more directly applies the
> evaluation order of operands, but I had a hard time coming up with any
> plausible examples where an implementor might have been pleased to do
> something other than what they thought best.

Some implementor might have been pleased to evaluate function arguments
left-to-right, for cultural reasons, but found it was "better" to
evaluate them right-to-left.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/10/2012 6:09:22 PM

On 09-Feb-12 20:27, Richard Harter wrote:
> On Wed, 08 Feb 2012 14:29:05 -0600, Stephen Sprunk
> <stephen@sprunk.org> wrote:
>> On 08-Feb-12 08:47, Richard Harter wrote:
>>> On Tue, 07 Feb 2012 16:51:17 -0600, Stephen Sprunk
>>> <stephen@sprunk.org> wrote:
>>>> On 07-Feb-12 15:50, Richard Harter wrote:
>>>>> Well, no, he isn't saying any such thing.  You just made it up.  The
>>>>> fact that evaluation order in C is left to the compilers has very
>>>>> little to do with optimization; it is a historical artifact that came
>>>>> from endorsing existing practice when the ANSI standard was put
>>>>> together.  Existing practice then was that compiler writers could do
>>>>> evaluations in whatever they pleased and they did.
>>>>
>>>> No, they did evaluations in the order that made the most sense (i.e. had
>>>> the best performance) for their particular implementation--and
>>>> implementations vary.
>>>
>>> You are not disagreeing with me.
>>
>> I disagree that they did "whatever they pleased"; they did what was best
>> for their particular implementation, for various definitions of "best".
> 
> Then if they did whatever they thought was best then that was what
> they pleased.  I'm not sure what you think "whatever they pleased"
> means. 

There are a great many things that would please me but which are not the
"best" thing to do.

>>>> For instance, varargs is more straightforward to implement with
>>>> right-to-left evaluation of arguments, at least with a stack-based
>>>> calling convention.  Order of evaluation may not matter for
>>>> register-based calling conventions, but if an implementation uses both,
>>>> it makes sense to use the same order.
>>>
>>> Well, yes, I know that.  However what you are talking about is a minor
>>> micro-optimization at most.
>>
>> It doesn't seem so minor, particularly for platforms where _every_ call
>> uses a stack-based calling convention.
> 
> Whoa.  The claim was about the cost of implementing varargs, something
> only used in a rather small number of cases.  For that matter, at the
> time varargs was not standardized.  Optimizing processing varargs was
> and is a micro-optimization, then and now.   

True, but it would be perverse to have right-to-left evaluation for
varargs calls but left-to-right evaluation for non-varargs calls.

In fact, a similar perversity actually exists in the wild: Win16/32 API
calls are evaluated left-to-right because the API specifies a "Pascal"
(push onto stack from left to right) calling convention, but non-API
calls will use a "C" (push onto stack from right to left) calling
convention.  So, two consecutive function calls may have two different
orders of evaluation!

>> Remember, we're talking about
>> long ago when compilers were rather dumb and most popular architectures
>> were register-starved.
> 
> Granted.  And it is also true that the generated code in the bodies of
> functions also suffered both because the architectures were limited
> and, quite bluntly, the quality of most implementations were limited.
> Furthermore evaluating function arguments right to left rather than
> left to right is an almost imperceptible micro-optimization when it is
> an optimization at all.  

Adding a few cycles to _every_ function call would add up; computers
back then were slow enough as it was.

>> That is the environment that ANSI was faced
>> with, and it would have been unreasonable to force the majority of
>> implementations to suffer a performance penalty for the questionable
>> benefit of left-to-right evaluation.
> 
> IMNSHO that performance penalty is much more fantasy than reality.  On
> the other hand the cost of reworking all of those compilers was a very
> real cost.  Quite reasonably, nobody wanted to pay that price.

I'm sure that was factored in as well.  Plus, there was a large base of
code that may have _depended_ on a particular order of evaluation.  If
nothing else, it would have been impossible to prove there wasn't.

> On the other hand there is a real benefit when all behaviours are well
> defined, when all code is either legal or illegal, and what the code
> is supposed to do can be determined by inspection of the code.  The
> qualility of C as a language would IMO be enhanced if most of these
> "undefined behaviours" were compilation errors.

True, but that is a luxury of developing standards _before_ amassing a
huge codebase.  That's not how C developed.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/10/2012 6:30:46 PM

On 02/10/2012 01:05 PM, Stephen Sprunk wrote:
> On 07-Feb-12 16:00, James Kuyper wrote:
....
>> True; but the fact that different current compilers give different
>> results cannot be used to validly infer that the behavior is undefined.
>> The behavior could be implementation-defined, or simply unspecified, or
>> one of the compilers you're comparing could be non-conforming.
> 
> True, divergent behavior could have been classified several different
> ways by the Standard.  I was merely pointing out that divergent behavior
> caused such classification, rather than the classification causing such
> divergent behavior as you seemed to be saying.

I think it was Nick who made the comments you're referring to, not me.
And a more accurate summary of what he said would be that the
classification allows the divergent behavior, rather than causing it.

The standard has had a major impact on compiler diversity. I know
because I remember what it was like before standard C was commonplace.
The committee didn't bless all existing variations in C compilers; some
variations were allowed by using one of those classifications, but most
were disallowed, and the ones that were disallowed rather quickly
disappeared. Unlike C99, C90 was adopted rather quickly.
0
Reply jameskuyper (5151) 2/10/2012 6:46:34 PM

In article <2MKdnZv4BcDflqnSnZ2dnUVZ_vadnZ2d@bestweb.net>,
Kenneth Brody  <kenbrody@spamcop.net> wrote:
>The efficient:
>
>     PUSH C
>     PUSH B
>     PUSH A
>
>versus the conforming:
>
>     SUB  SP,12
>     STOR [SP],A
>     STOR [SP+4],B
>     STOR [SP+8],C
>
>(Note, of course, that it is possible that there are machines on which the 
>calculated-store is faster than push, and may improve speed even with the 
>added stack-adjust, in which case it is certainly free to generate such 
>code.  The problem comes when you mandate it.)

I'm almost sure that the Pentium ran consecutive pushes two per cycle.

There is probably some window where this change was faster, but it seems
short-sighted; if the compiler guys had said 'we're going to use your
instructions like you said', i'm pretty sure that the hardware guys
would ensure that it's competitive.
0
Reply jgk1 (176) 2/10/2012 9:45:13 PM

On 2012-02-10, James Kuyper <jameskuyper@verizon.net> wrote:
> defective. In general, I'm a big believer in the concept that not all
> code needs to be portable - but this particular kind of non-portability
> doesn't seem to have any value.

Precisely! It is a "gratuitous" nonportability that is not linked to
any operating system or hardware issue. Gee, let's arbitrarily make certain
expression combinations have unspecified or undefined behavior, even though
they contain valid operations on valid operands.
0
Reply kaz15 (1129) 2/10/2012 10:24:30 PM

Kenneth Brody <kenbrody@spamcop.net> writes:

> On 2/9/2012 6:57 PM, Kaz Kylheku wrote:
>> On 2012-02-09, Kenneth Brody<kenbrody@spamcop.net>  wrote:
>>> On 2/8/2012 8:41 PM, John Bode wrote:
>>>> On Feb 8, 2:39 pm, Kenneth Brody<kenbr...@spamcop.net>   wrote:
>>> [...]
>>>>> The truth of the matter is, is that when, precisely, a side effect most
>>>>> efficiently takes effect, is very platform-dependent, and can even vary from
>>>>> expression to expression on a given platform.
>>>>>
>>>>
>>>> Is this anything more than received wisdom?  Does anyone have a
>>>> concrete example (read: generated machine code) showing *how*
>>>> rearranging evaluation order can make an operation more efficient?
>>>>
>>>> I mean, I've parroted that line more than once, but I certainly can't
>>>> point to an example of where it makes a difference.
>>>
>>> foo(a++,a++);
>>>
>>> On my system, this code is generated:
>>>
>>>           mov     eax, DWORD PTR _a
>>>           push    eax
>>>           push    eax
>>>           add     eax, 2
>>>           mov     DWORD PTR _a, eax
>>>           call    _foo
>>>           add     esp, 8
>>>
>>> By delaying the post-increment, the code is more efficient than requiring
>>> two separate increments.
>>
>> Note that this is still allowed under strict left-right, bottom-up evaluation.
>
> Not according to the "and all side-effects must take place
> immediately" part of the argument.  In that case, the second parameter
> *must* be one more than the original value of a.
>
>> Because a is not volatile, the code does not require two actual increments.
>> That is merely the abstract semantics.
>
> True, the as-if rule can be satisfied by the single "add 2" operation,
> but the "side-effects must take place immediately" cannot.

I don't follow this reasoning.  The as-if rule can be used to justify
removing the increments entirely (if a is not reference later, for
example) so I don't see why it can't be used to justify their happening
together.

<snip>
-- 
Ben.
0
Reply ben.usenet (6515) 2/10/2012 10:43:22 PM

On 2/10/2012 12:58 PM, Stephen Sprunk wrote:
> On 10-Feb-12 10:15, Kenneth Brody wrote:
>> On 2/9/2012 6:57 PM, Kaz Kylheku wrote:
>>> Because a is not volatile, the code does not require two actual
>>> increments.
>>> That is merely the abstract semantics.
>>
>> True, the as-if rule can be satisfied by the single "add 2" operation,
>> but the "side-effects must take place immediately" cannot.
>>
>> And, making "a" volatile gives this code:
>>
>>          mov     eax, DWORD PTR _a
>>          mov     ecx, DWORD PTR _a
>>          mov     edx, 1
>>          add     DWORD PTR _a, edx
>>          add     DWORD PTR _a, edx
>>          push    eax
>>          push    ecx
>>          call    _foo
>>          add     esp, 8
>>
>> Now, the two increments are done separately, but the code was still
>> rearranged so that they still take place after grabbing the original
>> values of "a".  Whether this is faster than moving one of the adds
>> between the two reads of "a", I don't know, nor do I have the time or
>> resources to investigate.
>
> "Faster" is perhaps irrelevant in this case because _the result is
> different_, which shows exactly why invoking undefined behavior can be
> such a problem.

Yes, "foo(a++,a++)" is UB.  However, the OP (I forget who that was at this 
point) was bemoaning the fact that UB exists, and suggested that C should 
make it defined, as Java does.

> The above asm does this:
>
> tmp1 = a;
> tmp2 = a;
> a = tmp1 + 1;
> a = tmp2 + 1;
> foo(tmp1, tmp2);
>
> Note that, despite two increments, the final value of a is only _one_
> greater than its initial value.

Re-read the assembler.  It's equivalent to:

     tmp1 = a;
     tmp2 = a;
     a++;
     a++;
     foo(tmp2,tmp1);

(Note, too, that the arguments are evaluated right-to-left, which is quite 
common, though not guaranteed.)

> This would not be a valid optimization if there were a sequence point
> between arguments, as proposed.

Correct.  Of course, given the lack of sequence points, it's perfectly 
valid.  :-)

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/10/2012 11:14:09 PM

On 2/10/2012 1:09 PM, Stephen Sprunk wrote:
> On 10-Feb-12 11:17, James Kuyper wrote:
>> I tried to come up with an example that more directly applies the
>> evaluation order of operands, but I had a hard time coming up with any
>> plausible examples where an implementor might have been pleased to do
>> something other than what they thought best.
>
> Some implementor might have been pleased to evaluate function arguments
> left-to-right, for cultural reasons, but found it was "better" to
> evaluate them right-to-left.

Hence the existence in some implementations of "extern pascal".  :-)

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/10/2012 11:17:30 PM

On Feb 9, 3:57=A0pm, Kaz Kylheku <k...@kylheku.com> wrote:
> On 2012-02-09, Kenneth Brody <kenbr...@spamcop.net> wrote:
>
>
>
>
>
>
>
>
>
> > On 2/8/2012 8:41 PM, John Bode wrote:
> >> On Feb 8, 2:39 pm, Kenneth Brody<kenbr...@spamcop.net> =A0wrote:
> > [...]
> >>> The truth of the matter is, is that when, precisely, a side effect mo=
st
> >>> efficiently takes effect, is very platform-dependent, and can even va=
ry from
> >>> expression to expression on a given platform.
>
> >> Is this anything more than received wisdom? =A0Does anyone have a
> >> concrete example (read: generated machine code) showing *how*
> >> rearranging evaluation order can make an operation more efficient?
>
> >> I mean, I've parroted that line more than once, but I certainly can't
> >> point to an example of where it makes a difference.
>
> > foo(a++,a++);
>
> > On my system, this code is generated:
>
> > =A0 =A0 =A0 =A0 =A0mov =A0 =A0 eax, DWORD PTR _a
> > =A0 =A0 =A0 =A0 =A0push =A0 =A0eax
> > =A0 =A0 =A0 =A0 =A0push =A0 =A0eax
> > =A0 =A0 =A0 =A0 =A0add =A0 =A0 eax, 2
> > =A0 =A0 =A0 =A0 =A0mov =A0 =A0 DWORD PTR _a, eax
> > =A0 =A0 =A0 =A0 =A0call =A0 =A0_foo
> > =A0 =A0 =A0 =A0 =A0add =A0 =A0 esp, 8
>
> > By delaying the post-increment, the code is more efficient than requiri=
ng
> > two separate increments.
>
> Note that this is still allowed under strict left-right, bottom-up evalua=
tion.
>
> Because a is not volatile, the code does not require two actual increment=
s.
> That is merely the abstract semantics.
>
> So this is really tangential to the debate. (Yes, rearranging computation=
s is
> important and crucial necessary for optimization.)

I'm sorry for potentially derailing this conversation, but this is one
of my pet peeves. You do know that volatile - apart from correct
signal handling and setjump longjump nonsense - is completely useless
in portable code, right? When you said "because a is not volatile",
you are immediately assuming several things about volatile which are
not true, and have never been true, and will not be true in C11. A
perfectly conforming implementation is free to basically ignore
volatile and compile it down as if it wasn't there. The semantics of
the C abstract machine do not specify what exactly a volatile write
"means". They just say that it's part of the visible behavior of the
abstract machine, while the standard does not define what that means.

As a matter of facts of current implementations, I have been told by
reliable people that volatile is insufficient alone to do MMIO on most
modern machines, rendering its original purpose moot. volatile is a
relic with no support from most compilers nowadays - apart from some
incredibly non-portable use in some kernel code, and with the advent
of C11, it should hopefully become extinct (again apart from setjump
longjump nonsense and legacy code).
0
Reply joshuamaurice (576) 2/10/2012 11:19:23 PM

On 2012-02-10, Jens Gustedt <jens.gustedt@loria.fr> wrote:
> Am 02/10/2012 05:24 AM, schrieb Shao Miller:
>> Is it realistic that an implementation might have a thread of execution
>> for each independent branch of evaluation, so that the evaluation order
>> of some expressions might be simultaneous?
>
> thread of execution in a broad sense, certainly, such as done for
> pipelining processors with out-of-order execution
>
> compilers do reordering of statements all the time, and not imposing a
> sequence point between two evaluations is giving the necessary slackness
> to the compiler for doing so.

That is false. A viable compiler must optimize across sequence points.
The necessary slackness comes from analyzing the data flows in the intermediate
graph structure representing the program.
0
Reply kaz15 (1129) 2/10/2012 11:32:42 PM

On 08-Feb-12 19:27, Kaz Kylheku wrote:
> On 2012-02-07, Stephen Sprunk <stephen@sprunk.org> wrote:
>> On 07-Feb-12 11:21, Kaz Kylheku wrote:
>>> - if an expression has several subexpressions, evaluate them left to right.
>>
>> Nice of you to dictate that people using systems that more efficiently
>> evaluate sub-expressions from right to left should suffer performance
>> degradation of all code, even in the majority of cases where the code is
> 
> Proof?

I've already provided one example.

>> well-written and therefore the order doesn't actually matter, simply
>> because it doesn't suit your sensibilities.
> 
> In the majority of cases, C code is not well-written. The history of C
> programming at large is riddled with crashing applications and operating
> systems, and exploitable security holes in online systems.

I disagree, but perhaps my perspective is limited by where I've worked.

>> If you /need/ to know that "foo(bar(), baz());" calls bar() before
>> baz(), then just write "tmp=bar(); foo(tmp, baz());".  There is no need
> 
> Thanks for the clueful suggestion, but, see, what I need to know first is
> WHERE this is hiding in a large code base.

I agree.  If C had a way to mark functions const/pure (as C++ does),
then it would be easy for compilers to flag a warning in cases where
unspecified order of evaluation might cause a problem; however, without
that ability, there would be far too many false positives for such a
warning to be useful.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Reply stephen (1122) 2/11/2012 3:57:07 AM

On 2012-02-10, Kenneth Brody <kenbrody@spamcop.net> wrote:
> On 2/10/2012 1:09 PM, Stephen Sprunk wrote:
>> On 10-Feb-12 11:17, James Kuyper wrote:
>>> I tried to come up with an example that more directly applies the
>>> evaluation order of operands, but I had a hard time coming up with any
>>> plausible examples where an implementor might have been pleased to do
>>> something other than what they thought best.
>>
>> Some implementor might have been pleased to evaluate function arguments
>> left-to-right, for cultural reasons, but found it was "better" to
>> evaluate them right-to-left.
>
> Hence the existence in some implementations of "extern pascal".  :-)

Order of argument evaluation is not calling convention.

extern pascal was needed to conform to a calling convention.
0
Reply kaz15 (1129) 2/11/2012 10:15:38 AM

On 2/11/2012 5:15 AM, Kaz Kylheku wrote:
> On 2012-02-10, Kenneth Brody<kenbrody@spamcop.net>  wrote:
>> On 2/10/2012 1:09 PM, Stephen Sprunk wrote:
>>> On 10-Feb-12 11:17, James Kuyper wrote:
>>>> I tried to come up with an example that more directly applies the
>>>> evaluation order of operands, but I had a hard time coming up with any
>>>> plausible examples where an implementor might have been pleased to do
>>>> something other than what they thought best.
>>>
>>> Some implementor might have been pleased to evaluate function arguments
>>> left-to-right, for cultural reasons, but found it was "better" to
>>> evaluate them right-to-left.
>>
>> Hence the existence in some implementations of "extern pascal".  :-)
>
> Order of argument evaluation is not calling convention.
>
> extern pascal was needed to conform to a calling convention.

You are, of course, correct.  While an implementation _typically_ evaluates 
arguments in the order it puts them in place for the call (whether that's 
pushing onto a stack, loading registers, or something else), it's certainly 
not a guarantee.

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/13/2012 9:04:24 PM

Kaz Kylheku <kaz@kylheku.com> writes:
> On 2012-02-07, Keith Thompson <kst-u@mib.org> wrote:
> > lujnan <lujnan@gmail.com> writes:
> >>> I don't want diagnostics; I want strict left to right evaluation order
> >>> of operands and subexpressions that complete their side effects before
> >>> yielding a value.
> >>
> >> i agree with your point of view.
> >
> > Then you don't want C.
> 
> You could say that to anyone who is working on the next standard.
> 
> Those who worked on C11 didn't want C99, and those who worked on C99
> didn't want C90.
> 
> > There are valid reasons for the way C leaves some expression evaluations
> > undefined. 
> 
> No, there are not. There are only outdated beliefs rooted in computer
> science shamanism.

Tosh. What was being asked for was the removal of CSE elimination for a 
start. Any compiler too dumb not to do CSE elimination is not one I'd 
chose to use, and any language that forbids CSE elimination is one I 
would have no interest in learning anything more about. This is not 
shamanism, this is common sense.

Phil
-- 
> I'd argue that there is much evidence for the existence of a God.
Pics or it didn't happen.
-- Tom (/. uid 822)
0
Reply thefatphil_demunged (1558) 2/21/2012 9:42:23 PM

jgk@panix.com (Joe keane) writes:
> In article <2MKdnZv4BcDflqnSnZ2dnUVZ_vadnZ2d@bestweb.net>,
> Kenneth Brody  <kenbrody@spamcop.net> wrote:
> >The efficient:
> >
> >     PUSH C
> >     PUSH B
> >     PUSH A
> >
> >versus the conforming:
> >
> >     SUB  SP,12
> >     STOR [SP],A
> >     STOR [SP+4],B
> >     STOR [SP+8],C
> >
> >(Note, of course, that it is possible that there are machines on which the 
> >calculated-store is faster than push, and may improve speed even with the 
> >added stack-adjust, in which case it is certainly free to generate such 
> >code.  The problem comes when you mandate it.)
> 
> I'm almost sure that the Pentium ran consecutive pushes two per cycle.

You remember correctly. push-after-push was a known often-used case 
that was optimised for. The latter of course has an AGI, which was 
very expensive on a Pentium. So from a 90's persective, the above
looks like H/W-optimised vs. S/W pessimised.

Phil
-- 
> I'd argue that there is much evidence for the existence of a God.
Pics or it didn't happen.
-- Tom (/. uid 822)
0
Reply thefatphil_demunged (1558) 2/21/2012 10:09:47 PM

On 2012-02-21, Phil Carmody <thefatphil_demunged@yahoo.co.uk> wrote:
> Kaz Kylheku <kaz@kylheku.com> writes:
>> On 2012-02-07, Keith Thompson <kst-u@mib.org> wrote:
>> > lujnan <lujnan@gmail.com> writes:
>> >>> I don't want diagnostics; I want strict left to right evaluation order
>> >>> of operands and subexpressions that complete their side effects before
>> >>> yielding a value.
>> >>
>> >> i agree with your point of view.
>> >
>> > Then you don't want C.
>> 
>> You could say that to anyone who is working on the next standard.
>> 
>> Those who worked on C11 didn't want C99, and those who worked on C99
>> didn't want C90.
>> 
>> > There are valid reasons for the way C leaves some expression evaluations
>> > undefined. 
>> 
>> No, there are not. There are only outdated beliefs rooted in computer
>> science shamanism.
>
> Tosh. What was being asked for was the removal of CSE elimination for a 
> start. Any compiler too dumb not to do CSE elimination is not one I'd 
> chose to use, and any language that forbids CSE elimination is one I 
> would have no interest in learning anything more about. This is not 
> shamanism, this is common sense.

CSE elimination in C compilers is not rooted in unspecified evaluation order,
but in the freedom to optimize, so long as the externally visible behavior
agrees in some ways with the abstract behavior. 

You don't have to evaluate a similar expression twice, if it makes no
difference (side-effect wise).

The following has to produce two x's, even now; though we don't know which
expression's x is printed first:

  putchar('x') + putchar('x');

the putchar('x') common subexpression can't be (entirely) reduced to one
instance because there is an external function call which may have a side
effect (and does).
0
Reply kaz15 (1129) 2/22/2012 4:28:14 AM

Kaz Kylheku <kaz@kylheku.com> writes:
> On 2012-02-21, Phil Carmody <thefatphil_demunged@yahoo.co.uk> wrote:
> > Kaz Kylheku <kaz@kylheku.com> writes:
> >> On 2012-02-07, Keith Thompson <kst-u@mib.org> wrote:
> >> > lujnan <lujnan@gmail.com> writes:
> >> >>> I don't want diagnostics; I want strict left to right evaluation order
> >> >>> of operands and subexpressions that complete their side effects before
> >> >>> yielding a value.
> >> >>
> >> >> i agree with your point of view.
> >> >
> >> > Then you don't want C.
> >> 
> >> You could say that to anyone who is working on the next standard.
> >> 
> >> Those who worked on C11 didn't want C99, and those who worked on C99
> >> didn't want C90.
> >> 
> >> > There are valid reasons for the way C leaves some expression evaluations
> >> > undefined. 
> >> 
> >> No, there are not. There are only outdated beliefs rooted in computer
> >> science shamanism.
> >
> > Tosh. What was being asked for was the removal of CSE elimination for a 
> > start. Any compiler too dumb not to do CSE elimination is not one I'd 
> > chose to use, and any language that forbids CSE elimination is one I 
> > would have no interest in learning anything more about. This is not 
> > shamanism, this is common sense.
> 
> CSE elimination in C compilers is not rooted in unspecified evaluation order,
> but in the freedom to optimize, so long as the externally visible behavior
> agrees in some ways with the abstract behavior. 
> 
> You don't have to evaluate a similar expression twice, if it makes no
> difference (side-effect wise).

Then it's not "strict", it's "as if". But the word "strict" was explicitly 
there above.

Phil
-- 
> I'd argue that there is much evidence for the existence of a God.
Pics or it didn't happen.
-- Tom (/. uid 822)
0
Reply thefatphil_demunged (1558) 2/24/2012 10:01:57 PM

On 2/21/2012 23:28, Kaz Kylheku wrote:
> The following has to produce two x's, even now; though we don't know which
> expression's x is printed first:
>
>    putchar('x') + putchar('x');
>

Doesn't that output a "bold 'x'" if they are evaluated simultaneously?
0
Reply sha0.miller (876) 2/25/2012 7:25:37 AM

On 2012-02-25, Shao Miller <sha0.miller@gmail.com> wrote:
> On 2/21/2012 23:28, Kaz Kylheku wrote:
>> The following has to produce two x's, even now; though we don't know which
>> expression's x is printed first:
>>
>>    putchar('x') + putchar('x');
>>
>
> Doesn't that output a "bold 'x'" if they are evaluated simultaneously?

Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?

6.5.2.2

10 There is a sequence point after the evaluations of the function
designator and the actual arguments but before the actual call.
Every evaluation in the calling function (including other function
calls) that is not otherwise specically sequenced before or after
the execution of the body of the called function is indeterminately
sequenced with respect to the execution of the called function. 94)

94)
In other words, function executions do not interleave with each other.
0
Reply ike7 (162) 2/25/2012 9:00:21 AM

Ike Naar wrote:
> On 2012-02-25, Shao Miller <sha0.miller@gmail.com> wrote:
> > On 2/21/2012 23:28, Kaz Kylheku wrote:
> >>    putchar('x') + putchar('x');
> > 
> > Doesn't that output a "bold 'x'" if they are evaluated
> > simultaneously?
> 
> Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?

Doesn't anybody here understand a joke?
0
Reply prl1 (101) 2/25/2012 7:13:06 PM

On Sat, 25 Feb 2012 11:13:06 -0800, Philip Lantz <prl@canterey.us>
wrote:

>Ike Naar wrote:
>> On 2012-02-25, Shao Miller <sha0.miller@gmail.com> wrote:
>> > On 2/21/2012 23:28, Kaz Kylheku wrote:
>> >>    putchar('x') + putchar('x');
>> > 
>> > Doesn't that output a "bold 'x'" if they are evaluated
>> > simultaneously?

This is a joke.

>> 
>> Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?

This also is a joke.
>
>Doesn't anybody here understand a joke?

Is this a joke?


0
Reply cri (1432) 2/25/2012 7:34:06 PM

On 2/25/2012 2:34 PM, Richard Harter wrote:
> On Sat, 25 Feb 2012 11:13:06 -0800, Philip Lantz<prl@canterey.us>
> wrote:
>
>> Ike Naar wrote:
>>> On 2012-02-25, Shao Miller<sha0.miller@gmail.com>  wrote:
>>>> On 2/21/2012 23:28, Kaz Kylheku wrote:
>>>>>     putchar('x') + putchar('x');
>>>>
>>>> Doesn't that output a "bold 'x'" if they are evaluated
>>>> simultaneously?
>
> This is a joke.
>
>>>
>>> Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?
>
> This also is a joke.
>>
>> Doesn't anybody here understand a joke?
>
> Is this a joke?

Besides, everyone knows that the "right way"[tm] to output a bold 'x' is:

     printf("\033[1m%c\033[0m",'x');

-- 
Kenneth Brody
0
Reply kenbrody (1860) 2/25/2012 9:51:38 PM

Ike Naar <ike@iceland.freeshell.org> wrote:
> On 2012-02-25, Shao Miller <sha0.miller@gmail.com> wrote:
> > On 2/21/2012 23:28, Kaz Kylheku wrote:
> >> The following has to produce two x's, even now; though we don't know which
> >> expression's x is printed first:
> >>
> >>    putchar('x') + putchar('x');
> >
> > Doesn't that output a "bold 'x'" if they are evaluated simultaneously?
> 
> Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?

This started out as a joke, but there's an important point to be made
here.  Note carefully 7.1.4p1:

	Any function declared in a header may be additionally
	implemented as a function-like macro defined in the header....
	Any invocation of a library function that is implemented as a
	macro shall expand to code that evaluates each of its arguments
	exactly once, fully protected by parentheses where necessary, so
	it is generally safe to use arbitrary expressions as
	arguments.186)

	186) Such macros might not contain the sequence points that the
	corresponding function calls do.

So, although you're guaranteed that actual function calls aren't executed
simultaneously, there's no guarantee that library routines are actually
implemented as function calls unless you're careful to avoid any
potential macro version.
-- 
Larry Jones

Honey, are we out of aspirin again? -- Calvin's Dad
0
Reply lawrence.jones2 (565) 2/27/2012 9:12:34 PM

On 2012-02-27, lawrence.jones@siemens.com <lawrence.jones@siemens.com> wrote:
> Ike Naar <ike@iceland.freeshell.org> wrote:
>> On 2012-02-25, Shao Miller <sha0.miller@gmail.com> wrote:
>> > On 2/21/2012 23:28, Kaz Kylheku wrote:
>> >> The following has to produce two x's, even now; though we don't know which
>> >> expression's x is printed first:
>> >>
>> >>    putchar('x') + putchar('x');
>> >
>> > Doesn't that output a "bold 'x'" if they are evaluated simultaneously?
>> 
>> Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?
>
> This started out as a joke, but there's an important point to be made
> here.  Note carefully 7.1.4p1:
>
> 	Any function declared in a header may be additionally
> 	implemented as a function-like macro defined in the header....
> 	Any invocation of a library function that is implemented as a
> 	macro shall expand to code that evaluates each of its arguments
> 	exactly once, fully protected by parentheses where necessary, so
> 	it is generally safe to use arbitrary expressions as
> 	arguments.186)
>
> 	186) Such macros might not contain the sequence points that the
> 	corresponding function calls do.
>
> So, although you're guaranteed that actual function calls aren't executed
> simultaneously, there's no guarantee that library routines are actually
> implemented as function calls unless you're careful to avoid any
> potential macro version.

Would parenthesizing the function name, as in

    (putchar)('x') + (putchar)('x');

be sufficient to make sure the non-macro verion is used?
0
Reply ike7 (162) 2/27/2012 10:42:45 PM

On 2/27/2012 17:42, Ike Naar wrote:
> On 2012-02-27, lawrence.jones@siemens.com<lawrence.jones@siemens.com>  wrote:
>> Ike Naar<ike@iceland.freeshell.org>  wrote:
>>> On 2012-02-25, Shao Miller<sha0.miller@gmail.com>  wrote:
>>>> On 2/21/2012 23:28, Kaz Kylheku wrote:
>>>>> The following has to produce two x's, even now; though we don't know which
>>>>> expression's x is printed first:
>>>>>
>>>>>     putchar('x') + putchar('x');
>>>>
>>>> Doesn't that output a "bold 'x'" if they are evaluated simultaneously?
>>>
>>> Doesn't 6.5.2.2 p 10 forbid simultaneous evaluation?
>>
>> This started out as a joke, but there's an important point to be made
>> here.  Note carefully 7.1.4p1:
>>
>> 	Any function declared in a header may be additionally
>> 	implemented as a function-like macro defined in the header....
>> 	Any invocation of a library function that is implemented as a
>> 	macro shall expand to code that evaluates each of its arguments
>> 	exactly once, fully protected by parentheses where necessary, so
>> 	it is generally safe to use arbitrary expressions as
>> 	arguments.186)
>>
>> 	186) Such macros might not contain the sequence points that the
>> 	corresponding function calls do.
>>
>> So, although you're guaranteed that actual function calls aren't executed
>> simultaneously, there's no guarantee that library routines are actually
>> implemented as function calls unless you're careful to avoid any
>> potential macro version.
>
> Would parenthesizing the function name, as in
>
>      (putchar)('x') + (putchar)('x');
>
> be sufficient to make sure the non-macro verion is used?

That's described in the same paragraph.  Also described is #undef usage.
0
Reply sha0.miller (876) 2/27/2012 11:54:05 PM

113 Replies
36 Views

(page loaded in 0.727 seconds)

Similiar Articles:


















7/13/2012 10:14:59 AM


Reply: