subroutine stack and C machine model

S

Seebs

<http://cm.bell-labs.com/cm/cs/who/dmr/cman.pdf> is the C Reference
Manual that came out with 6th Edition Unix in May 1975. In section 7,
it says:

Otherwise the order of evaluation of expressions is undefined. In
particular the compiler considers itself free to compute
subexpressions in the order it believes most efficient, even if
the subexpressions involve side effects.

This further undermines Spinny's theory. Consider that the C implementation
in V6 UNIX was probably not defined in any way by concern about what other
compiler vendors had done. Rather, it was solely defined in terms of the
observed needs and the opportunities for optimization available to them at
the time.

Which is to say: It was never the result of the alleged "careless mistake",
but was a considered decision.

This makes it possible for someone who feels it's wrong to disagree with the
priorities set by the designers, but ludicrous to claim that it was an
accident, oversight, or done in response to mysterious "vendors".

(I wish I now remembered who it was that I argued with some years back
about this very issue, I think it was in the mid-90s, but it might
have been the lateish 90s. He was firmly convinced that C should have
specified order of evaluation.)
The expressions In parentheses are evaluated (in an unspecified
order) to rvalues and assigned to the function's parameters.

My guess would be that this was a specific instance of the same general
rule.
<http://www.masswerk.at/algol60/modified_report.htm>, the Modified
Report on the Algorithmic Language Algol 60, says:
The order of evaluation of primaries within an expression is not
defined. If different orders of evaluation would produce different
results, due to the action of side effects of function
designators, then the program is undefined.

Now, the question is: Does "undefined" mean the same thing here that it
would in C (as in, "undefined behavior" being a pure wildcard), or does it
merely mean that they don't commit to which order of evaluation would have
been used?

-s
 
N

Nick Keighley

I've worked with a lot of people with physics or electronics degrees.
I didn't find the CS people significantly *worse* at programming.
There seemed to be a different set of skills. The electronics people
naturally had a closer to the hardware attitude, had less problems
with parallelism and "thought in assembler". When I wrote assembler I
thought in an HLL and then compiled it in my head. They skipped the
HLL stage. CS people seemed to be better at information hiding,
modularisation etc. ("what's the problem with global varaibles? I use
loads of them" "we know"). Some physics/electronics people seemed not
to understand the why of encapsulation at all (which seems odd for
electronics people). The hardware people seemed to be much more
willing to learn new stuff (by definition- they've changed fields).
I've bumped into quite a few CS who seem to think education finishes
when you graduate. A dumb idea in this field!

That book is quite possibly the worst I've ever bought. Even
"Numerical Recipes" is better.

I like design patterns. It often seemed to formalise what I'd been
trying to achieve. And it gave me an alternative to deeply nested
inheritance trees, which had always given me the willies. But I agree
GoF in the hands of an enthuiast can be a nightmare.


--
- Note:
- I wanted to put a check in getGuiExtract(), but it's a void
method, inherited from the father of the father of the father of
the
father of the father of the father of the father of the
father ...

So I can't modify its interface.

[comment found in C++ program- edited for length]
 
N

Nick Keighley

I'm curious:  What about it do you dislike (or should I ask that elsewhere)?

I have a copy of that, along with a ton of other books, which I've variously
read or skimmed or whatever.  My impression of DP was sort of ambivalent...
I'm not sure why, but it just seemed like it would be likely to yield a lot
of mis-applied designs.  It may be one of those things where having them
handy and being familiar with them is useful to an experienced programmer,
but if you aren't experienced enough, they're just dangerous.

I'm much more interested by the notion of "antipatterns", which I think are
in some ways a better way to learn about software, and certainly something
people ought to be aware of.  (I say this having inherited a database design
that I was able to get onto the front page of the Daily WTF at one point.)

http://www.amazon.co.uk/Anti-patter...=sr_1_1?ie=UTF8&s=books&qid=1256893363&sr=8-1

not as good as the Patterns book but worth skimming
 
N

Nick Keighley

[email protected] (Richard Tobin) said:
To me, it seems self-evidently false.

not sure about /self-evidently/ false. I think it's false. More
information about intent *is* useful to optimisers. Though whether
specifing order of evalution is useful is debatable.
If some particular order of evaluation allows for easier optimisation,
any C compiler may assume that that order was explicitly intended
(since any order is permitted) and may therefore get the supposed
benefit.  As far as the compiler is concerned, I don't see how there
can be any benefit to a specified order of evaluation that can't be
realised in a language that permits any order.

I suppose an optimiser has more work to do if order isn't specified-
it has to try every possible ordering. But that wan't what spinoza was
claiming
 
N

Nick Keighley

"users" and "compiler magic" are meaningless and barbaric words.

they aren't meaningless they are widly used and understood. A "user"
of a compiler is someone who, er, uses it. I cannot see why this is
ambiguous or barbaric. "compiler magic" might be translated as
"optimisation technique"
 
N

Nick Keighley

the defendant was clearly abusing a transitive operator during the
hours of darkess
Nick, Nick : do you really think he believes it does?

I've no idea what he believes I was trying to be clear
 
N

Nick Keighley

Right. The problem was that given specific compilers for given
specific machines generally stayed with one way or another in cases
like this, and programmers mistook this behavior for a property of C.
Moreover, I would guess that in more than nine out of ten cases the
order of evaluation was left to right.

Well, this fact, alongside the fact that other languages stay with
left to right,

I gave you a list of ones that didn't.

means that K&R and the standard erred, since they
created a hidden fact. It should have been cleaned up in the standard,
and would have been if the standard was in the public interest. It was
not cleaned up to preserve vendor investment.
liar


Nor is it necessary for optimization: the above reversal is possible
for the most common case when a and b are simple constants or lValues
without aliasing, and whether they are can be determined by the
optimizer.

I gave a more plausible example later on in my post

It was a hoax in Schildt's case because Schildt's experience and
knowledge on the vastly most prevelant platforms were valuable to real
people, to the extent that the existence and popularity of Schildt's
book should have been a reason to correct the standard.

just like ISO fixed the Pascal standard to match Borland's
implementation.

Instead, sponsored by vendors,
liar


the standards committee performed an adolescent
stunt by preserving a completely unnecessary property of C, one that
is mostly invisible to intelligent C programmers.

most intelligent users are aware of this property of C and of many
other languages. Probably the vast majority of programming languages
have this property.
[...] since 'a' and b are potentially arbitarily complicated
expressions it could make a difference
   i = g();
   a = i + j;
   s = f() + a;

by stashing a away before the call to f() you could save
recalculating it.
 
B

bartc

In the workplace, I've taught several CS graduates. They didn't know
spit about programming. None of them. (I fixed that.) Of course, it
would be wrong to conclude that every CS graduate is ignorant of
programming, but it is clear to me from personal experience that a CS
degree is not sufficient to guarantee that a candidate will be able
to write computer programs (*at all*, never mind /good/ computer
programs).

There's seems to be a lot of CS-graduate-bashing going on.

If you're talking about fresh graduates who haven't done any work placement,
then it's not unexpected that they will lack practical experience. Not
unlike a newly qualified driver who nevertheless will know a lot more than
you about the latest regulations and driving techniques.

And just as in other fields, some will be better than others.

(Maybe all the best graduates got jobs elsewhere, while the rest ended up
with jobs at your place, who knows...)

(In my case I couldn't get a programming job at all and ending up designing
digital hardware despite no qualifications, and no qualified colleagues to
help out either; but the stuff I made seemed to work fine... For some things
degrees should not be treated too seriously)
 
D

Dik T. Winter

>
> darn I tried to find that and failed!

It is in the "modified report" (1976), not in the "revised report" (1963).
The revised report is silent on it, and at that time (~1970) my understanding
was strict left-to-right evaluation (as all the compilers of that time did).
 
S

Seebs

not sure about /self-evidently/ false. I think it's false. More
information about intent *is* useful to optimisers. Though whether
specifing order of evalution is useful is debatable.

I think the thing is this:

If you define order of evaluation, you REMOVE information about intent,
because it's no longer possible to tell an intended order of evaluation
from one which was merely a side-effect of the language mandating one.

So it guarantees that you have less information about intent.

I don't think this is quite self-evident, but I think it is certainly
demonstrable.

-s
 
S

Seebs

The main skill a good programmer can have is the ability to make an
informed decision on what works in a time/cost balance and to work in a
team and adhere to project standards. There are many in c.l.c that I can
never imagine working in a team of any kind.

Huh. That's weird. In general, most of the active participants here (most,
not all) strike me as people who'd be pretty fun to work with.

-s
 
B

Ben Pfaff

Seebs said:
Huh. That's weird. In general, most of the active participants here (most,
not all) strike me as people who'd be pretty fun to work with.

I always find myself wondering whether I'd be able to work well
with some of the folks who have coding styles quite different
from mine. For example, Richard Heathfield advocates strongly
against "goto" (or at least states that he hasn't used it in a
long time) and, I believe, more than one point of return in a
function. But I regularly use "goto" to jump forward to cleanup
code at the end of a function and often return from multiple
places in a single function. I don't know how happy I'd be
having to give these techniques and, conversely, I don't know how
happy he'd be reviewing my code that does use them.
 
S

Seebs

I always find myself wondering whether I'd be able to work well
with some of the folks who have coding styles quite different
from mine. For example, Richard Heathfield advocates strongly
against "goto" (or at least states that he hasn't used it in a
long time) and, I believe, more than one point of return in a
function. But I regularly use "goto" to jump forward to cleanup
code at the end of a function and often return from multiple
places in a single function. I don't know how happy I'd be
having to give these techniques and, conversely, I don't know how
happy he'd be reviewing my code that does use them.

I guess I tend to view clashes like that as pretty minor and easily
resolved. I'd expect either of you to be pretty easy to get along
with. The only people I'd expect to have trouble with would be the
pure kooks (ala Spinny), and the status-obsessed people. Everyone
else would probably do fine, I'd think.

-s
 
B

Ben Pfaff

Seebs said:
I always find myself wondering whether I'd be able to work well
with some of the folks who have coding styles quite different
from mine. For example, Richard Heathfield advocates strongly
against "goto" (or at least states that he hasn't used it in a
long time) and, I believe, more than one point of return in a
function. But I regularly use "goto" to jump forward to cleanup
code at the end of a function and often return from multiple
places in a single function. I don't know how happy I'd be
having to give these techniques and, conversely, I don't know how
happy he'd be reviewing my code that does use them.

I guess I tend to view clashes like that as pretty minor and easily
resolved. I'd expect either of you to be pretty easy to get along
with. [...]

You might be right.

Hey, let's try it out. Any comp.lang.c regulars need a job? My
company is hiring ;-)
 
S

Seebs

Hey, let's try it out. Any comp.lang.c regulars need a job? My
company is hiring ;-)

I'm pretty much set for jobs these days. I'm super happy at dayjob; I
get to be the guy who tells people that no, it's not a compiler bug.

We get some awesome code through.

Okay, time to make a topical post:

struct foo {
int type;
short len;
short this;
long that;
unsigned char scratch[FOO_HEADER_LEN];
unsigned char data[512];
};

Given this, an attempt to reference "foop->data - FOO_HEADER_LEN" can
give a warning about something being outside array bounds from gcc.
The question is: Why would you be doing that in the first place? (There
is an answer, and it is not 100% stupid.) Given that you really do have
a reason to do the crazy thing, is theer a way you can do it which
doesn't create an array bounds problem?

-s
 
B

Ben Pfaff

Seebs said:
struct foo {
int type;
short len;
short this;
long that;
unsigned char scratch[FOO_HEADER_LEN];
unsigned char data[512];
};

Given this, an attempt to reference "foop->data - FOO_HEADER_LEN" can
give a warning about something being outside array bounds from gcc.
The question is: Why would you be doing that in the first place? (There
is an answer, and it is not 100% stupid.)

I'm not sure whether it's 100% stupid or not, but sometimes this
kind of issue comes up in network or file data formats. You
have, for example, 14 (FOO_HEADER_LEN) bytes of Ethernet header
that you really don't care about, followed by some amount of data
that you do care about, but for API reasons you have to read it
all into one contiguous block of memory. (And you know that the
compiler won't insert padding.)
Given that you really do have a reason to do the crazy thing,
is theer a way you can do it which doesn't create an array
bounds problem?

Write foop->scratch instead? Dimension the data as unsigned char
buffer[FOO_HEADER_LEN + 512]?
 
S

Seebs

Seebs said:
struct foo {
int type;
short len;
short this;
long that;
unsigned char scratch[FOO_HEADER_LEN];
unsigned char data[512];
};
Given this, an attempt to reference "foop->data - FOO_HEADER_LEN" can
give a warning about something being outside array bounds from gcc.
The question is: Why would you be doing that in the first place? (There
is an answer, and it is not 100% stupid.)
I'm not sure whether it's 100% stupid or not, but sometimes this
kind of issue comes up in network or file data formats. You
have, for example, 14 (FOO_HEADER_LEN) bytes of Ethernet header
that you really don't care about, followed by some amount of data
that you do care about, but for API reasons you have to read it
all into one contiguous block of memory. (And you know that the
compiler won't insert padding.)

Very good.
Write foop->scratch instead?

They weren't totally confident that there would be no padding between
scratch and data, and I wasn't able to convince myself that I could
prove that would be a safe assumption, even though it seems obvious
that there shouldn't be.
Dimension the data as unsigned char
buffer[FOO_HEADER_LEN + 512]?

For some reason they wished to avoid that.

My solution:

(((unsigned char *)foop) + offsetof(struct foo, data) - FOO_HEADER_LEN)

If there are N bytes of padding between scratch and data, this gives you
FOO_HEADER_LEN - N bytes of scratch, plus the padding, plus data. But
that's probably okay in this case.

-s
 
B

Ben Pfaff

Seebs said:
struct foo {
int type;
short len;
short this;
long that;
unsigned char scratch[FOO_HEADER_LEN];
unsigned char data[512];
};
They weren't totally confident that there would be no padding between
scratch and data, and I wasn't able to convince myself that I could
prove that would be a safe assumption, even though it seems obvious
that there shouldn't be.

I use build assertions for this kind of thing. With a suitable
definition of BUILD_ASSERT, I would add something like this:

BUILD_ASSERT(offsetof(struct foo, scratch)
+ sizeof(((struct foo*)0)->scratch)
== offsetof(struct foo, data));

I wish C had better syntax for the size of a struct member.
 
K

Kenny McCormack

Huh. That's weird. In general, most of the active participants here (most,
not all) strike me as people who'd be pretty fun to work with.

So goes the hymnal.
 
S

Seebs

So goes the hymnal.

Well, that's the thing. The reason you're not one of the "most" is that
you're constantly viewing everything in terms of status, rather than in
terms of functionality. The last thing I want on a team is people who
are spending more time comparing epeen than they are working. It's the
polar opposite of effective teamwork.

Maybe that works okay with a group consisting entirely of people who think
status is important, and insist on interpreting everyone else's behavior
in terms of what it would mean if it had been motivated entirely by status
instead of by any other consideration. But somehow I don't think it does.

-s
 

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,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top