Syntax for union parameter

J

James Kuyper

Until I switch from compiler A to compiler B ... then C becomes useless.

Why? Properly written code will have it's behavior unchanged as a result
of that switch. Improperly written code stands a good chance of having
it's defects revealed.
I would argue that having C without standards has allowed the creation
of niche empires. A developer with a large code base dare not migrate
away from a toolset, lest they face so many bugs that it makes it
impossible to execute.

Luckily, C does have standards - just not the ones you want it to have.
The standards it does have allow the developer to explicitly specify the
order, when it matters, and allow the implementor to reorder the code
for platform-specific efficiencies, when the developer indicates that
the order doesn't matter. The only problem comes from people who don't
know enough about the language to know how to specify the order, when it
matters.

....
The behavior of 'a = a[i++]' is undefined. Your solution is to
drastically change the language definition so that the behavior is
defined. My solution is to write it more clearly, for example:
a = a[i+1];
i++;


I'm penning the language definition for RDC.


You're using C as one of several sources of inspiration for your RDC
definition - at least, that's the excuse you've given for repeatedly
using a forum devoted to C to discuss RDC. The changes he's referring to
are the changes between C and RDC.
 
R

Rick C. Hodgin

Why? Properly written code will have it's behavior unchanged as a result
of that switch. Improperly written code stands a good chance of having
it's defects revealed.

Not much code translates 100% between popular compilers.
Luckily, C does have standards - just not the ones you want it to have.
The standards it does have allow the developer to explicitly specify the
order, when it matters, and allow the implementor to reorder the code
for platform-specific efficiencies, when the developer indicates that
the order doesn't matter. The only problem comes from people who don't
know enough about the language to know how to specify the order, when it
matters.

Yes, that's one opinion. :)
The behavior of 'a = a[i++]' is undefined. Your solution is to
drastically change the language definition so that the behavior is
defined. My solution is to write it more clearly, for example:
a = a[i+1];
i++;

I'm penning the language definition for RDC.


You're using C as one of several sources of inspiration for your RDC
definition
Correct.

- at least, that's the excuse you've given for repeatedly
using a forum devoted to C to discuss RDC. The changes he's referring
to are the changes between C and RDC.


I understand (and understood).

Best regards,
Rick C. Hodgin
 
G

glen herrmannsfeldt

Keith Thompson said:
(snip)

Apples-to-apples comparisons (for C as it's currently defined) are
entirely possible. Just compare the speed of the generated code for C
source code whose behavior is well defined by the C standard. (Behavior
of code whose behavior is undefined is not relevant in the context of C.
Feel free to care about it yourself if you so choose, but expect me to
ignore you on that particular point).

Well, for one, speed optimization isn't always the goal. There have
been, at least, compilers that had a choice of optimizing for speed
or size.
C has done quite well *without* defining the order of evaluation
of most expressions.
(snip)

I didn't know this one about Java, but for Java the ordering of
exceptions is pretty important. If you call more than one method
in a statement, it is pretty important that the calls be in the
right order.
FWIW, I tested the a = a[i++] code in Visual C++, GCC, and G++.
It works as I specified in GCC and G++, and the exact opposite way in
Visual C++. I would find that completely unacceptable were I to encounter
such a thing in normal programming. With RDC, it won't be an issue.
It may produce slightly slower code on one platform, but at 3GHz and
higher ... who cares for 99.9% of applications. For the other .1%,
write some custom assembly, or re-write the algorithm.

It's your expectations that are the root of the problem.
As far as C is concerned, and as far as I personally am concerned, the
behavior of `a = a[i++]` *simply doesn't matter*. Why does it
matter to you? Would you seriously write a line of code like that in
real-world code?

In most cases, code whose behavior is undefined because of evaluation
order issues is also just plain poorly written code.

Yes, write for readability. There are a few rare cases where speed
is so important that one should write unreadable code to make it
fast enough. (Or for the IOCCC.)
The behavior of `a = a[i++]` is undefined. Your solution is to
drastically change the language definition so that the behavior is
defined. My solution is to write it more clearly, for example:

a = a[i+1];
i++;


There really aren't that many places where it is better to put
the i++ inside the expression. In the case of loops, I pretty
much always try to put it in the for statement, even if it isn't
as obvious as the usual for loops.

One interesting thing is that Java doesn't have the C comma operator.
Java pretty carefully kept the C operators, as far as I know to make
it easier for C programmers to learn. (That is, closer than C++.)

Even though Java doesn't have the comma operator, it does allow
multiple expressions in the first and third part of the for statement,
the place they most commonly exist in C code.
"By definition, and for all time". By *what* definition (other than one
you've made up)? It's difficult to take you seriously when you write as
if your personal preferences were Fundamental Truths of the Universe.

As long as you are following the truths of the universe, don't forget
that the universe is left handed.

-- glen
 
K

Keith Thompson

Rick C. Hodgin said:
So the apples-to-apples comparison is for those things defined in C.
Anything left up to the implementation cannot be compared. Useful. :)

Yes, how else could it be? It's a direct consequence of the fact that C
leaves certain things undefined.

[...]
Until I switch from compiler A to compiler B ... then C becomes useless.
I would argue that having C without standards has allowed the creation
of niche empires. A developer with a large code base dare not migrate
away from a toolset, lest they face so many bugs that it makes it
impossible to execute.

Do you have personal experience to back that up?

There's plenty of C code that's reasonably portable across different
compilers.

There's also plenty of non-portable C code, that depends on a certain
toolset and/or a certain target platform. One of C's greatest strengths
is the ability to develop *non-portable* code when that's necessary.

But the order of evaluation of subexpressions is not, in my experience,
a major source of non-portability. Sensible programmers don't write
code whose behavior depends on evaluation order in ways that aren't
defined by the language.
They said the same thing to Philo Farnsworth: "Send moving pictures
through invisible air? Lunatic!"

"They laughed at Columbus, they laughed at Fulton, they laughed at the
Wright brothers. But they also laughed at Bozo the Clown."
-- Carl Sagan
As far as C is concerned, and as far as I personally am concerned, the
behavior of 'a = a[i++]' *simply doesn't matter*. Why does it
matter to you?


It doesn't. It's an example demonstrating the thing I do care about:
order of operation.


*Why* do you care so much about order of operation?

C is a tool for getting things done. If I write something like

x = foo(y) + bar(z);

I *do not care* whether foo or bar is called first. If I did care, I'd
write the code differently:

x = foo(y);
x += bar(z);
I would do it on a bet or a dare, or if I was trying to prove a point,
or maybe to sneak in some code to amuse and confuse those who come after
me who will be examining my code. I can't imagine a case where I would
write code like that as a matter of course, however.

Then why does it matter to you what it does?

[...]
I believe that this methodology of writing code is better than the other
choices. The authors of GCC agree with me. The authors of Microsoft's
compiler disagree with me. And I'm sure if we got another 10 compiler
authors lined up they'd have varying opinions as well. It is simply
that mine fall on the side of the exact order required to carry out the
instruction, and in no other order, and using whatever exists at that
point based on any prior modifications.

How do you infer that the authors of gcc agree with you? Is it because
some obcure expression, when compiled with gcc, happens to yield the
result you like? That means nothing. The result is entirely arbitrary,
and I seriously doubt that the gcc maintainers share your opinions about
order of evaluation. Try feeding 100 similar expressions to gcc, and I
doubt that the majority of them will be evaluated the way you want.

Think of it this way. If you write (x + y) and feed it to a C compiler,
you are explicitly telling the compiler something like: "Generate code
that computes the sum of x and y, evaluating the operands in any order
you like". If that's not what you want to do, don't tell the compiler
to do that. If you want a specific order of evaluation for some reason,
you can specify it in C (though probably not as tersely as an expression
that doesn't specify the order).
 
R

Robbie Brown

snip


While that's true, C was a very early example of a language that did
this. Most of the languages you know and love that do this today (Java,
JavaScript to name but two) took the concept from C but specified it
more rigorously.

I'm dubious that we'll ever know the motives behind some of the early
design decisions but several vaguely plausible ones are:
- because it makes writing the compiler easier
- because it makes the compiler run faster
- because no-one thought about the problem and by the time someone did
there was already heaps of code that assumed one behaviour or the other
- because on a popular architecture of the day there was a logical way
to map this to the machine code and so no-one bothered to specify it
further.

Generally though C leaves a lot more things unspecified (or defined as
undefined!) to allow the compiler maximum freedom to reorder and
restructure code to best suit the target architecture.

When I was first presented with the 'undefined' argument I took it to
mean that the behavior of something that was undefined would be random
and randomly fatal (possibly) but that's not how it appears to be
turning out. If I try the a = a[i++] thing on my current machine the
result is always the same, regardless of what came before or comes after
that particular line of code. So, as far at the specification is
concerned the behavior may well be undefined but it appears to be very
well defined for this compiler on this machine. I do get the point
however that just because it works that way in this case doesn't mean it
will work the same way on a different machine with different compiler.

Having spent many years writing serverside business components in Java
the idea that something works 'here' but not 'there' is taking some
getting used to. The only problem I ever encountered with Java was when
attempting to run code compiled against a later release on a VM of an
earlier release. Also Java is 'controlled' by a single entity, if you
want your implementation of the spec to be called 'Java' you had better
make sure it passes certification. The situation with C appears to be
different ... since when has anything 'designed by committee' ever been
coherent?
 
K

Kaz Kylheku

Suppose that array int a[] contains { 1, 2, 3 }, and int i is 0.
After the execution of a = a[i++], what should be the values in a[]?
Why?


I think a[0] contains 'U' and a[1] contains 'B'.


:) UB3... :)

After a = a[i++], the correct answer will always be:

a[0] is 1
a[1] is 1
a[2] is 3

The reasoning is the sequence of operations:

// a = a[i++];
t1 = i; // i of "i++"
i = i + 1; // ++ of "i++"
t2 = a[t1]; // value of "a[i++]"
a = t2; // stored into "a"

If C does not define this behavior to be exactly this, shame on C.


No it doesn't (shame on C, I completely agree).

The point of the exercise is that languages have specifications,
and not everything in those specifications can be inferred by experimenting
with your compiler or even reading its documentation, and that specifications
are not only for compiler writers to worry about.

The left hand side of the assignment, a = could in fact use either the prior
value of i, or the new value. Or even some half-baked value.

The behavior is not defined, because a certain rule is violated: namely that if
an object is modified in an expression, then its value can only be accessed for
the purpose of determining the new value. (Here it is accessed elsewhere in the
expression for another purpose: determining where a store takes place in an
array).
RDC defines this behavior to be exactly this ... it is ALWAYS the order of

Have you written this down somewhere? What is the specification?
operations as is being computed.

What is "order of operations?". If we have (EXPR1) + (EXPR2), which
one is evaluated first? The + operator doesn't say; "order of operations",
as children learn it in school, means that in A*B+C, the multiplication is done
first. The values of A, B and C can be obtained in any order, because there
are no side effects in pure arithmetic.
 
D

David Brown

So the apples-to-apples comparison is for those things defined in C.
Anything left up to the implementation cannot be compared. Useful. :)

There are (basically) three types of behaviour that the C standards
discuss. Standards-defined behaviour, which must implemented by all
conforming compilers, covers the great majority of real-world code.
Implementation-defined behaviour covers functionality that can vary
between compilers, but which should be consistent within a given
compiler and work as documented by the compiler (such as whether an
"int" is 32-bit, 16-bit, etc.). Undefined behaviour covers cases that
the standards say is not valid C code even though it follows the syntax.

Apples-to-apples comparison is for standards defined behaviour.
Implementation-dependent gets more complicated, but can often be
usefully compared. But for things that are specifically undefined
behaviour, the code makes no sense and thus there can be no sensible
comparison.
Until I switch from compiler A to compiler B ... then C becomes useless.

As long as you write proper C, then there is no problem. If you want to
write some sort of mess that is syntactically correct and happens to be
accepted by the compiler, but is undefined, then you can't expect to
rely on getting the same nasal daemons from two different compilers.
I would argue that having C without standards has allowed the creation
of niche empires.

You are arguing from a position of total ignorance - you have apparently
no concept of why C has such undefined behaviour, or why some aspects
are left to the compiler implementer, and you have strongly resisted all
our attempts to enlighten you.

C has been standardised since 1989 - and the standards explicitly say
that the ordering of actions between sequence points is not defined, and
that code that depends on a particular ordering (such as "a =
a[i++]") has undefined behaviour.
A developer with a large code base dare not migrate
away from a toolset, lest they face so many bugs that it makes it
impossible to execute.

There are many reasons why it is a good idea to stick to particular
toolsets for particular projects, especially in areas such as embedded
programming - but this is not one of them. Only if the programmers do
not understand the language they are using, yet insist on writing
dangerous and badly designed code (usually in an attempt to be "smart"),
could you see such situations from changing compiler.
They said the same thing to Philo Farnsworth: "Send moving pictures
through invisible air? Lunatic!"

You have made your expectations perfectly clear, and we are telling you
that they do not match reality. Putting your hands over your ears and
singing "la, la, la" does not change that.
As far as C is concerned, and as far as I personally am concerned, the
behavior of 'a = a[i++]' *simply doesn't matter*. Why does it
matter to you?


It doesn't. It's an example demonstrating the thing I do care about:
order of operation.


The statement "a = a[i++]" is meaningless. Can you find an example
of real-world, clearly written code whose intention is clear and where
the order of evaluation actually matters?
Would you seriously write a line of code like that in real-world code?

I would do it on a bet or a dare, or if I was trying to prove a point,
or maybe to sneak in some code to amuse and confuse those who come after
me who will be examining my code. I can't imagine a case where I would
write code like that as a matter of course, however.
In most cases, code whose behavior is undefined because of evaluation
order issues is also just plain poorly written code.
Agreed.

The behavior of 'a = a[i++]' is undefined. Your solution is to
drastically change the language definition so that the behavior is
defined. My solution is to write it more clearly, for example:
a = a[i+1];
i++;


I'm penning the language definition for RDC. There are no drastic
changes. This is how I have always had it in mind to be.
"By definition, and for all time". By *what* definition (other than one
you've made up)?

None. It is the one I have determined.
It's difficult to take you seriously when you write as if your personal
preferences were Fundamental Truths of the Universe.

I believe that this methodology of writing code is better than the other
choices.


You can believe that for your own language - but you cannot make up
beliefs about other languages.
The authors of GCC agree with me.

No, they disagree with you. They think the order of operations is
undefined, and the compiler can generate code that works best for the
particular target in question. By sheer chance, it happened to match
your ideas in this particular case.

Incidentally, when I tried "a = a[i++]" with gcc it gave me a warning
"operation on 'i' may be undefined". Which is a nice result.
The authors of Microsoft's compiler disagree with me.

The authors of Microsoft's compiler disagree with you, but not in the
way you think - they agree with the gcc authors. It is just luck that
their compiler picked a different implementation of this particular example.
And I'm sure if we got another 10 compiler
authors lined up they'd have varying opinions as well.

They would all have the same opinion, if they are good compiler authors.
They would have read the standards and understood what is meant by
undefined ordering. It could be that they would give their compiler a
defined ordering - they are free to do so - but that would be because it
is easier to do that than to make the compiler more flexible.
 
J

James Kuyper

On 02/07/2014 04:02 AM, Robbie Brown wrote:
....
When I was first presented with the 'undefined' argument I took it to
mean that the behavior of something that was undefined would be random
and randomly fatal (possibly) but that's not how it appears to be
turning out.

"undefined" means that the standard imposes no requirements on the code.
It doesn't mean "random" or "fatal", though those are possible
consequences. The key fact is that "undefined behavior" gives
implementations the freedom to design their implementation without
having to worry about the possibility of something going wrong if it
code with undefined behavior is processed. That doesn't guarantee that
anything actually will go wrong, only that going wrong is a possibility.
And if something does go wrong, it generally won't go wrong randomly -
it will go wrong in a way that makes a lot of sense, if you know enough
about how the implementation is designed.

For example, one of the most basic kinds of undefined behavior is
attempting to access memory before the beginning of an array, or after
the end of the array. As far as the standard is concerned, any thing
could happen, but in practice, overwhelmingly the most common behavior
is that array[n], where n is greater than the length of array, is
converted into code that takes the address of the start of the array,
adds n*sizeof(array[0]) bytes to that address, reads the memory at the
resulting address, interprets that memory as if it contained an object
of the array's element type, and returns the corresponding value. All of
the "randomness" comes from not knowing what object is is that is
actually stored at that address. The possibility for fatal results comes
mainly from the possibility that the resulting address points to either
non-existent memory, or memory your process doesn't have permission to
access. To a lesser extent, fatal results can occur because the memory
contains bits that correspond to a trap representation for the array's
element type.

....
concerned the behavior may well be undefined but it appears to be very
well defined for this compiler on this machine.

The other key point is that "undefined behavior" is a piece of C
standard jargon - it has a special meaning which is NOT "behavior for
which there is not definition". What it actually means is "behavior for
which the C standard imposes no requirements". It's entirely possible
that something other than the C standard does impose its own
requirements: the operating system, the hardware, or the C
implementation itself. Taking code for which the C standard does not
define the behavior, and defining what the behavior will be, is one of
the common ways a fully conforming implementation of C can implement an
extension.
 
R

Rick C. Hodgin

How do you infer that the authors of gcc agree with you?

Because it generates code as I've indicated (that the assignment location
is determined after the value to be populated is computed). Microsoft's
developers disagree with me, because it generates code contrary to the
manner I've indicated.
Is it because
some obcure expression, when compiled with gcc, happens to yield the
result you like? That means nothing.
No.

The result is entirely arbitrary,

No. There are no arbitrary things done in coding something like this.
It may have been the result of an arbitrary decision, but I doubt it.
The people who write GCC most likely determined that such a solution
was desirable, rather than relying upon a coin toss to choose for them.
and I seriously doubt that the gcc maintainers share your opinions about
order of evaluation. Try feeding 100 similar expressions to gcc, and I
doubt that the majority of them will be evaluated the way you want.

Prepare the source code with 100 similar expressions and I'll do just that.
Think of it this way. If you write (x + y) and feed it to a C compiler,
you are explicitly telling the compiler something like: "Generate code
that computes the sum of x and y, evaluating the operands in any order
you like". If that's not what you want to do, don't tell the compiler
to do that. If you want a specific order of evaluation for some reason,
you can specify it in C (though probably not as tersely as an expression
that doesn't specify the order).

I suppose it goes back to the nature of the function call. On the stack,
left-most function call parameters are pushed first. As such, right-to-left.

Best regards,
Rick C. Hodgin
 
J

James Kuyper

Because it generates code as I've indicated (that the assignment location
is determined after the value to be populated is computed).

But people who disagree with you are perfectly capable of creating
compilers that would generate such code. If an implementor believes,
unlike you, that the standard does not need to specify the order, they
are free to choose any order they find convenient, which has at least a
50% chance of being the same as the order you think should be mandatory.
How do you know that isn't the case here?
... Microsoft's
developers disagree with me, because it generates code contrary to the
manner I've indicated.

That, on the other hand, is solid evidence of a disagreement of some
kind. They might believe that the standard should specify the order they
chose. On the other hand, they might believe that the standard should
not specify the order, and they happened to choose a different order
than you approve of - but either way, they're disagreeing with you.
No. There are no arbitrary things done in coding something like this.
It may have been the result of an arbitrary decision, but I doubt it.
The people who write GCC most likely determined that such a solution
was desirable, rather than relying upon a coin toss to choose for them.

That's almost certainly true - but it's also possible that their
determination that it was desirable was context-dependent, and that in a
different context the compiler would choose a different order.

....
I suppose it goes back to the nature of the function call. On the stack,
left-most function call parameters are pushed first. As such, right-to-left.

I gather that the most convenient order depends upon details of how the
machine language works. That's one reason why the order is NOT specified
by C.

When a type has to be emulated in software, rather than having direct
hardware support, operations involving that type often are converted to
function calls. Otherwise, the fact that evaluation of the operands of
most binary operators is unspecified is a distinct issue from the fact
that the order of evaluation of function arguments is unspecified.
 
D

David Brown

Because it generates code as I've indicated (that the assignment location
is determined after the value to be populated is computed). Microsoft's
developers disagree with me, because it generates code contrary to the
manner I've indicated.

Do you ever actually /read/ other posts in this newsgroup? Or do you
just decide that you know all the facts - including the history of C and
its standards, and the minds of the people who wrote gcc and MSVC - and
then repeat those "facts" blindly?

No. There are no arbitrary things done in coding something like this.
It may have been the result of an arbitrary decision, but I doubt it.
The people who write GCC most likely determined that such a solution
was desirable, rather than relying upon a coin toss to choose for them.

Look up "arbitrary" in a dictionary.
Prepare the source code with 100 similar expressions and I'll do just that.


I suppose it goes back to the nature of the function call. On the stack,
left-most function call parameters are pushed first. As such, right-to-left.

Again, you are making wild generalisations about C based on some
examples you have seen. Here are some /real/ facts for you:

C makes no guarantees about the order that function parameters are
evaluated.

Different compilers will evaluate things in different orders, and the
same compiler may use different orders at different times. The ordering
does not have to be left-to-right or right-to-left - it can be any mixture.

C does not require the use of a stack, even though it is very common. I
have used two different C compilers without any sort of data stack. The
compilers were somewhat limited, due to the limitations of the target
processor, and were perhaps not 100% standards compliant - but they
supported function calls without a data stack.

It is common for at least some parameters to be passed in registers
rather than the stack.

It is common for ABI's to specify that the right-most parameter gets
stacked first, at least for functions with a variable number of
parameters. For example, by pushing the right-most parameters first, a
function like "printf" can pop the first parameter off the stack without
knowing the number of parameters.

C compilers can always use the "as if" rule - they must generate code
that works "as if" it were running on a conceptual C virtual machine
that strictly obeys the standards. When the compiler can safely do so,
it can re-arrange code, inline function calls, etc. As long as the
final result is the same /as if/ the code had followed the ordering
specified (when the ordering /is/ specified), it can use whatever object
code ordering it wants.
 
B

Ben Bacarisse

Robbie Brown said:
Having spent many years writing serverside business components in Java
the idea that something works 'here' but not 'there' is taking some
getting used to.

That's natural. C was designed in the 70s to be a low-level language
that is a bit more portable the B (which was nothing by the type-less
bit-shuffling language). Java was designed in the 90s to be as portable
as possible -- the VM is intended to remove any dependency on the
underlying hardware. A lot of the undefined things in C are there
to permit the compiler to be "cheap": shifts can do whatever the
hardware does, and the undefined evaluation order can save a register
here and there depending on the machine instruction set.
The situation with C
appears to be different ... since when has anything 'designed by
committee' ever been coherent?

That may be true, but is there anything incoherent going on in this
case?
 
K

Keith Thompson

David Brown said:
As long as you write proper C, then there is no problem. If you want to
write some sort of mess that is syntactically correct and happens to be
accepted by the compiler, but is undefined, then you can't expect to
rely on getting the same nasal daemons from two different compilers.

There's plenty of C code that depends on compiler-specific extensions
and other characteristics -- and if you need to use those extensions,
there's nothing wrong with that.

The Linux kernel, for example, can't be compiled by C compilers other
than gcc (or compilers closely compatible with gcc). Plenty of
Windows-specific code depends on Microsoft's compiler. And so forth.

[...]
C has been standardised since 1989 - and the standards explicitly say
that the ordering of actions between sequence points is not defined, and
that code that depends on a particular ordering (such as "a =
a[i++]") has undefined behaviour.


It's not quite that simple. For example, the behavior of this:

printf("foo") + printf("bar");

depends on the order of evaluation of the operands of the "+" operator,
but the behavior is not undefined. It must (attempt to) print either
"foobar" or "barfoo"; which one it prints is *unspecified*.
 
K

Kenny McCormack

Because it generates code as I've indicated (that the assignment location
is determined after the value to be populated is computed). Microsoft's
developers disagree with me, because it generates code contrary to the
manner I've indicated.

1) I agree with you, Rick. C would be a better language if it were
completely standardized. And by that I mean that the results are
predictable (see below for more on this). But it isn't, and we have to
live with that.

2) If you want D, you know where to find it. Or RDC...

Note: The fact is that C is not a "safe" language. And by safety, I mean
at least the following 3 things:

1) The behavior of any syntactically valid program is predictable and
consistent (across implementations).

2) The behavior of any syntactically valid program is safe (none of
this crashing your system, reformatting your hard drive, or nasal
daemons stuff). I'm sure we all remember the first time we found
out that a perfectly reasonable, syntactically valid C program
could easily crash your system (for example, if you allocate too
big of an automatic [aka, "stack"] array).

3) Runtime errors are caught and handled sensibly (without the
programmer having to do anything - i.e., write error handler code for
every system call, as in C). Normally, this means generating a
sensible error message and aborting the program.

--
But the Bush apologists hope that you won't remember all that. And they
also have a theory, which I've been hearing more and more - namely,
that President Obama, though not yet in office or even elected, caused the
2008 slump. You see, people were worried in advance about his future
policies, and that's what caused the economy to tank. Seriously.

(Paul Krugman - Addicted to Bush)
 
R

Rick C. Hodgin

But people who disagree with you are perfectly capable of creating
compilers that would generate such code.

Seriously, James? Are we back to this (again). *SIGH* This will be my
last post to you on any issue relating to whether or not compiler authors
agree with me.

The scope here is "on this point." The GCC compiler authors agree with
me (on this point) because they wrote their compilers to operate as I
have indicated. Regardless of their underlying motives, this is what
they wrote. It is the way I have indicated. We are in agreement (on
this point).
If an implementor believes,
unlike you, that the standard does not need to specify the order, they
are free to choose any order they find convenient, which has at least a
50% chance of being the same as the order you think should be mandatory.
How do you know that isn't the case here?

It doesn't particularly matter how they arrived at their decision. At
some point a decision was made, and (as I indicated elsewhere) I believe
it was not due to a coin toss, but rather a thoughtful consideration, but
regardless, thereafter a plan was in motion. They had a purpose, a
direction, a "GCC Standard" which must be adhered to ... the one which
agrees with my position.

In short, we are in agreement (on this point). They agree with me (on
this point). I agree with them (on this point).
That, on the other hand, is solid evidence of a disagreement of some
kind.

Seriously? When we're in agreement, it cannot be true? And when we're
in disagreement it's patently clear that it is true? NO! I cannot
believe that you are really like this, James. It's amazing me. I'm
literally sitting here beside myself.

*SIGH* By your own line of reasoning whether or not they actually
disagree with me cannot be known. For example, you say that the GCC
authors could've disagreed with me, but for whatever reason chose to
code in the manner I prescribe. Well, the same applies here, James.

The Microsoft authors could've agreed with me, but for whatever reason
chose to code in a manner contrary to the one I prescribe.

It cannot be both ways (that GCC doesn't agree with me, yet Microsoft
definitely does disagree with me). So, I choose to accept the fact
that the proof is in the published product, and they agree or disagree
based upon that criteria.
They might believe that the standard should specify the order they
chose. On the other hand, they might believe that the standard should
not specify the order, and they happened to choose a different order
than you approve of - but either way, they're disagreeing with you.

Applying this same logic to GCC, either way, their authors are agreeing
with me.
That's almost certainly true - but it's also possible that their
determination that it was desirable was context-dependent, and that
in a different context the compiler would choose a different order.

I think that's one of the advantages of the GCC compiler toolchain:
that it's multi-platform, and there aren't staunch variations like
this across implementations. Perhaps between version 4.5 and 4.6
there are changes, but all 4.5 on all platforms should work nearly
perfectly, as will all 4.6 versions, and so on.

Oops! I obviously meant right-most function call parameters are
pushed first (as such, right-to-left).
I gather that the most convenient order depends upon details of how the
machine language works. That's one reason why the order is NOT specified
by C.

I don't know. I can see arguments either way. The first is the nature
of the early C compiler implementations. They were parsing parameters
left-to-right on the line, and they parsed all the way through to make
sure it was a valid syntax before encoding it. That meant recursion
through the parameters, and then explicit code generation writes on the
way back out. I could be wrong, but it is at least one possibility.

I've never seen a language that pushes left-to-right, but all of them
push right-to-left. My experience here is limited to x86 and ARM
implementations using various toolsets, but is by no means comprehensive.
When a type has to be emulated in software, rather than having direct
hardware support, operations involving that type often are converted to
function calls. Otherwise, the fact that evaluation of the operands of
most binary operators is unspecified is a distinct issue from the fact
that the order of evaluation of function arguments is unspecified.

Yeah, I would argue that today on modern CPUs it makes little difference.
I'm sure the C standards I've seen (of right-to-left) now exist for backward
compatibility reasons. However, I still believe it's the right way to
perform that operation (due primarily to the general form of the equal
assignment syntax -- right, then left).

I did see an interesting proposal once which didn't matter on direction:

x -> y // Same as y = x;
y <- x // Same as y = x;

The -> and <- indicate direction, so you can compute in the order desired.

Best regards,
Rick C. Hodgin
 
K

Keith Thompson

Rick C. Hodgin said:
Because it generates code as I've indicated (that the assignment location
is determined after the value to be populated is computed). Microsoft's
developers disagree with me, because it generates code contrary to the
manner I've indicated.

The behavior of gcc and of Microsoft's compiler is entirely consistent
with their authors actually understanding the C standard, an in
particular understanding that the order of evaluation of the operands of
most operators is arbitrary. I find it vanishingly unlikely that gcc's
authors agree with your point of view; they know the language too well
for that.
No. There are no arbitrary things done in coding something like this.
It may have been the result of an arbitrary decision, but I doubt it.
The people who write GCC most likely determined that such a solution
was desirable, rather than relying upon a coin toss to choose for them.

Perhaps, but you have no basis for concluding that they followed the
same line of reasoning you have.
Prepare the source code with 100 similar expressions and I'll do just that.

How about just one?

#include <stdio.h>
int main(void) {
int arr[] = { 10, 20, 30, 40, 50, 60 };
int i = 0;
arr[i++ + ++i] = i++ + ++i;
for (int i = 0; i < sizeof arr / sizeof arr[0]; i ++) {
printf("%d ", arr);
}
putchar('\n');
}

Using gcc 4.7.2, the output without optimization is:

10 20 4 40 50 60

With optimization, the output is:

10 20 30 40 4 60
I suppose it goes back to the nature of the function call. On the stack,
left-most function call parameters are pushed first. As such, right-to-left.

That may happen to be true for some implementations. It is not
required, or even implied, by the C language standard.

Re-read the above paragraph, starting with "Think of it this way".
Repeat until you understand it. Consider the possibility that
you're wrong. Because you are.
 
K

Kenny McCormack

Keith Thompson said:
Re-read the above paragraph, starting with "Think of it this way".
Repeat until you understand it. Consider the possibility that
you're wrong. Because you are.

There you go with the insults again.
 
J

James Kuyper

Seriously, James? Are we back to this (again). *SIGH* This will be my
last post to you on any issue relating to whether or not compiler authors
agree with me.

The scope here is "on this point." The GCC compiler authors agree with
me (on this point) because they wrote their compilers to operate as I
have indicated. Regardless of their underlying motives, this is what
they wrote. It is the way I have indicated. We are in agreement (on
this point).

If the point was, whether one particular piece of code should be
evaluated in that order, when compiled for a particular target machine,
with a particular set of compiler options, then yes, the fact that gcc
did generate code that evaluated the operands in that order, under those
circumstances, does prove that they agreed with you, on that point.

However, change even a single character in your program, or change one
compiler option, or change the target system, and it's entirely possible
that you'll find gcc generating code that evaluates the operands in the
other order.

I had thought that your point was more general than that? I had thought
your point was your claim that the C standard should always specify the
precise order of evaluation of all sub-expressions, and that this should
specify the same order as the one that you personally considered to the
right one.

No single example (in fact, no finite number of examples) of how gcc
compiles code can prove that the gcc implementors agree with you on that
more general point. It could be disproven by observing gcc generating
different orders in different circumstances. It can be disproven by
talking with the developers, or by examining records of their design
documents or their design discussions. However, no matter how many
examples you find in which they always use the same order you approve
of, the very next example might show the other order, so no finite
number of such examples can show that they agree with you.
Seriously? When we're in agreement, it cannot be true? And when we're
in disagreement it's patently clear that it is true? NO! I cannot
believe that you are really like this, James. It's amazing me. I'm
literally sitting here beside myself.

There's three options: they
A) believe that the order should always be left-to-right
B) believe that the order should, in some cases, be left-to-tight, and
at other cases, be right-to-left
C) believe that the order should always be right-to-left

No finite number of examples can disprove B; unless you know which cases
they consider relevant. That opinion is perfectly consistent with any
arbitrarily long list of cases in which the exact same order was chosen.
However, a single counter-example is sufficient to disprove either of
the other two possibilities. Your one example with gcc cannot disprove
that they believe B. But a single counter-example from Microsoft can
disprove that they believe it should always be the same order as
whichever one you consider appropriate.

*SIGH* By your own line of reasoning whether or not they actually
disagree with me cannot be known. For example, you say that the GCC
authors could've disagreed with me, but for whatever reason chose to
code in the manner I prescribe. Well, the same applies here, James.

No it doesn't, because of the difference between the belief that a
particular fixed evaluation order should be used, and the belief that it
should be different in different cases. A single counter-example is
sufficient to disprove holding of the first belief, while no finite
number of examples can disprove holding of the second (unless you know
which cases matter, in which you can choose the examples to explore
those cases).
The Microsoft authors could've agreed with me, but for whatever reason
chose to code in a manner contrary to the one I prescribe.

Do you have any reason why you would have chosen to code in a manner
contrary to the one that you yourself have prescribed? If so, then in
what sense have you prescribed it? If not, they they are in disagreement
with you, if only with regard to whether or not the reason they had was
sufficient to justify ignoring your prescription.

.....
I think that's one of the advantages of the GCC compiler toolchain:
that it's multi-platform, and there aren't staunch variations like
this across implementations. Perhaps between version 4.5 and 4.6
there are changes, but all 4.5 on all platforms should work nearly
perfectly, as will all 4.6 versions, and so on.

Do you have evidence of to support your claim that they fail to take
advantage of platform-specific optimizations? I know that they allow you
to explicitly request a very large array of different platform-specific
optimizations. That their default optimizations would never be
platform-dependent suggests far less competence than I thought they had.

Also, by "context", I was not just referring to the platform. The
sub-expression of an assignment expression might be evaluated in one
order in one place, and in a different order in a different place within
the same program being compiled for a particular platform. Among the
things likely to influence this decision is the kind of expression being
evaluated, and whether or not nearby code provides opportunities to
evaluate common sub-expressions only once, rather than multiple times.
I don't know. I can see arguments either way.

If you don't know of a specific platform where there are very good
reasons for using the opposite direction from the one you think should
be mandatory, then you don't know enough to weigh in on this issue. Such
platforms do exist, though I personally couldn't tell you which ones
they are. My specialty is portable code - I know what's possible, and I
know how to write my code to work regardless of which possibility comes
up, but I've no need to remember which systems that possibility actually
comes up for. People with more knowledge of specific platforms could
probably identify them for you.
 
R

Rick C. Hodgin

The behavior of gcc and of Microsoft's compiler is entirely consistent
with their authors actually understanding the C standard, an in
particular understanding that the order of evaluation of the operands of
most operators is arbitrary. I find it vanishingly unlikely that gcc's
authors agree with your point of view; they know the language too well
for that.

Bottom line:

GCC = processes as I indicate
MS = processes opposite as I indicate

This is by default in the default (non-optimized) parser.
Perhaps, but you have no basis for concluding that they followed the
same line of reasoning you have.

I never concluded the GCC authors followed the same line of reasoning.
That thought has never entered into my mind. I concluded that their
final conclusion was as mine is, that a = a[i++] should process the
value first, and then do the assignment second (with the address of a
being computed at that time).
Prepare the source code with 100 similar expressions and I'll do just that.

How about just one?
#include <stdio.h>
int main(void) {
int arr[] = { 10, 20, 30, 40, 50, 60 };
int i = 0;
arr[i++ + ++i] = i++ + ++i;
for (int i = 0; i < sizeof arr / sizeof arr[0]; i ++) {
printf("%d ", arr);
}
putchar('\n');
}

Using gcc 4.7.2, the output without optimization is:
10 20 4 40 50 60
With optimization, the output is:
10 20 30 40 4 60


A flaw in the optimization engine, or one which takes advantage of the
fact that there is no hard definition on this type of behavior as is
defined in C (again, a flaw in the optimization engine that it produces
inconsistently executing code as per its unoptimized form).

I recognize C is this way. It is incomplete.
That may happen to be true for some implementations. It is not
required, or even implied, by the C language standard.

I recognize C is this way. It is incomplete.
Re-read the above paragraph, starting with "Think of it this way".
Repeat until you understand it. Consider the possibility that
you're wrong. Because you are.

Your conclusion that I am wrong is based on things which are not part of
my thoughts, considerations, or positions. You are ascribing concluded
positions to what you believe to be my true thoughts on something, but
you are in error. For example, you believe that I believe that the GCC
authors followed the same line of reasoning I did as to why a = a[i++]
is processed as I indicate, when in fact I never thought they followed
along with my same line of reasoning ... only that they came to the same
conclusion I did in the end, and now that they are there, it is an
inertial point moving forward that must be adhered to for backward
compatibility.

Best regards,
Rick C. Hodgin
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,127
Latest member
CyberDefense
Top