bunch of pedants

G

Geoff

Er, wasn't a Mars Rover stuck because of a buffer overrun in its C code?

Which rover?

Sprit was almost lost due to an over-allocation of file system space
in the flash memory causing it to fail and reboot but recovery was
successful.
 
K

Keith Thompson

Bartc said:
The regulars are technically correct. But being technically correct is not
always helpful.
[...]

But it was in this case.

Take a look at the "Why are variables stored on the stack?" thread
from which this one was spawned. We corrected the OP's mistaken
assumption *and* discussed the issue he raised at considerable length.
 
M

Morris Dovey

My suspicion is that adding stack operations would force a
completely new architecture, and I doubted that such a move could
be made without bloodshed. It's likely easier to introduce a
completely new product line.

I guess I was wanting to believe that someone in the systems
development group figured out a way to shoehorn stack
manipulation op codes into the already-full set. :p

Thanks.
 
Y

ymuntyan

The regulars go on denying that C uses a stack. They should
read this:

<begin quote>
Any function in C may be recursive
(without special declaration) and most possess several "automatic"
variables local to each invocation. These characteristics suggest
strongly that a stack must be used to store the automatic variables,
caller's return point, and saved registers local to each function;
in turn, the attractiveness of an implementation will depend heavily
on the ease with which a stack can be maintained.
<end quote>

This was written by an expert in C.

The best joke in that other thread was about this text not
being normative.

[snip]
Facts are not important. The C standard does not mention a stack,
and that is it.

True. One says "C insists on something", and bunch of
people will fight it using the Holy Standard. They will
pretend that it makes sense too. Funny how they don't
notice that "insists" is not a standard term, perhaps
because they wouldn't be able to use the standard otherwise.

[snip]
I decided that it is a waste of time to discuss with them. They just
repeat their bullshit without caring about what you answer to them

Personally I will not answer any more to falcolner and co. "C has no
stack" for them? Let it be.

Yes please just let it be. Is it comp.lang.c or what?

Yevgen
 
B

Ben Bacarisse

Older IBM systems had no stack support.
Admittedly, it's been a while since I wrote assembler for an IBM
mainframe,
Ditto.

but R13 had no push/pop capability.

Absolutely. The S/360 and S/370 had no stack and no associated
register. Later mainframes may well have done -- I moved to
mini-computers.
By convention (and
only by convention) is was used to point to an area of storage
(called a "SAVEAREA") retrieved by making a system call via
programed interrupt (issuing an SVC) using code generated by a
GETMAIN macro invocation. That system call was approximately
analogous to a malloc() call.

That is how I remember it. I have to hand the System 370 Principles
of Operation, and there is not support for any stack in hardware. The
recommended register conventions (and as you say, they were just that)
were:

R0 used to store the return value
R1 pointed to an argument list
R13 pointer to an 18-word register save area (usually static)
R14 return address
R15 address of function to call

I'd outline the standard calling convention, but that is getting even
more off-topic. It is slightly on topic in that it does not work for
C. The standard calling sequence worked fine for old FORTRAN but the
design had no hardware help for recursive functions.
If anyone on CLC has enough personal experience (or can look at a
dump of an actual program), I'd be interested in learning exactly
how this stack has been implemented.

Sadly, I don't remember. All I can remember is the standard, static,
non-stack calling conventions.

It is interesting to note that the two languages I used on the old 360
were FORTRAN IV (for which a stack is not required) and LISP (for
which a stack is not quite sufficient). It was the 70s that saw the
supremacy of a half-way house between languages that did not support
recursion and those that had first-class functions -- BCPL, C, Pascal,
Ada etc.
 
M

Morris Dovey

Gordon said:
IBM loved assembly-language macros. It would have been possible
to define PUSH and POP macros without actually changing the instruction
set. For that matter, it's not unheard of to have assembly-language
"opcodes" expand to more than one instruction (in effect, hardcoded
macros built into the assembler).

Yuppers - this is why I asked about examining a program dump. :)

The S/360 and S/370 instruction set was implemented in microcode,
so the option was always there to drop an instruction and use
that op code for something else.

For one project we used just the CPU (without core) of S/360 and
wrote the entire application in microcode to achieve necesary
speed. It could truck right along when it didn't have to waste
time fetching, decoding, executing, loading, and storing!

The 33FD (8" flexible diskette) started out as a device for
boot-time loading of microcode in a large OOS. That system never
made it to market, but the FD caught on passably well. :-D
 
G

Gordon Burditt

My suspicion is that adding stack operations would force a
completely new architecture, and I doubted that such a move could
be made without bloodshed. It's likely easier to introduce a
completely new product line.

It was *possible* to make a stack out of the existing S360/370
architecture. (By that I mean a stack that is a contiguous block
of storage used in a last-in-first-out ordered by address.) You
could allocate a block of memory big enough for a bunch of save
areas, then use load/store-through-register-indirect instructions
preceeded or followed by subtract immediate or add immediate
instructions to adjust R13 for the appropriate save area. (The
more commonly used techniques were the static save area and one
allocated with GETMAIN.)

Mixing linkage conventions like this would be a nightmare if it was
used between programs, though.

There wasn't a single PUSH or POP instruction that I recall, but
you could do it with two instructions. You also get to decide
whether the stack grows up or down, and have several hardware stack
pointers. You might even manage to make this work properly with
existing OS code. A problem comes when the OS calls *YOUR* code
with one of its own save areas in use. Some of the "OS exit"
routines didn't document whether the effect was that of a direct
branch or whether you'd be nested by several save areas deep.

Some people back in the early '70s used the technique of extending
a save area to provide local storage for recursive routines (close
analogy to C auto variables). But there was no contiguous block
of storage you could call the "stack". It was in fragmented pieces
all over static storage and/or GETMAIN-allocate storage. I don't
call that a "stack" even though it works in a LIFO manner.
I guess I was wanting to believe that someone in the systems
development group figured out a way to shoehorn stack
manipulation op codes into the already-full set. :p

IBM loved assembly-language macros. It would have been possible
to define PUSH and POP macros without actually changing the instruction
set. For that matter, it's not unheard of to have assembly-language
"opcodes" expand to more than one instruction (in effect, hardcoded
macros built into the assembler).
 
C

CBFalconer

Keith said:
.... snip ...

Then why did you start a new thread?


I am not CBFalconer. Please do not try to put his words in my
mouth, or mine in his. I do not say this to criticize him, or
even necessarily to disagree with him, but to refute your
apparent belief that everyone who disagrees with you must be
making the same arguments.

Time for a thread plonk.
 
M

Mark McIntyre

Bartc said:
The problem is, someone posts a question about C and X, but X is not a term
in the standard, so immediately it is denied that X is possible at all. End
of post.

Well, thats generally just not true. Most of the regulars here will post
at length explaining /why/ X isn't in the standard, and just what X is.

The posts stating flatly that its not for discussion tend to arise when
someone insists they know better than everyone else even when good
reasons have been given. Or when they're obsessed.
In fact X may be true on most implementations -- or at least on 100% of the
implementations the poster is interested in --

But then there are /lots/ of things which are true on 100% of a selected
set of implementations. If all you use is Windows, then 100% of your
platforms have complicated graphics. If you use Sun servers, tehy
probably all have HBAs and multiple processors. Going further, 100% of
all known implementations involve the movement of electrical fields.

None of these are anything to do with C though.
 
C

Chris Torek

Er, wasn't a Mars Rover stuck because of a buffer overrun in its C code?
[/QUOTE]

Which rover?

(I do not know which one he means.)
Sprit was almost lost due to an over-allocation of file system space
in the flash memory causing it to fail and reboot but recovery was
successful.

I know something about this, and it was not really a "buffer overrun"
at all, but rather due to a change in the use of the file system
on vxWorks on the hardware in question. The system was tested with
a small number of files, and configured to handle only a small
number of files. Some time before or shortly after launch, however,
someone decided to load a bunch of new files to the flash without
deleting the old ones. Since the system was configured to handle
only a small number of files, it was unable to progress with the
large number in place. (The solution was simple: delete the unneeded
files, which -- as I heard it -- were left behind simply because
they were not sure if the new files were right, yet.)

One of the morals, as it were, is: test the system you will use,
in the way you will use it. :) If you plan to keep lots of files
around, test the system that way. (Of course, the vxWorks file
system implementation was eventually modified so as to not place
this small fixed limit on the maximum number of files. That
particular change happened well before I ever did anything to the
vxWorks dosFs implementation myself, so I am a bit fuzzy on the
exact problem with the dosFs 1 implementation. The dosFs 2
implementation still has a limit on the number of simultaneously
*open* files, for various reasons, but one can have as many
file-system-resident files as will fit in the directory area, as
long as one does not try to open all of them at the same time.
For FAT32, there is no hard limmit at all, since even the root
directory is handled via an expandable cluster chain.)
 
S

stop

jacob navia said:
The regulars go on denying that C uses a stack. They should
read this:

<begin quote>
Any function in C may be recursive
(without special declaration) and most possess several "automatic"
variables local to each invocation. These characteristics suggest
strongly that a stack must be used to store the automatic variables,
caller's return point, and saved registers local to each function;
in turn, the attractiveness of an implementation will depend heavily
on the ease with which a stack can be maintained.
<end quote>

This was written by an expert in C.

True, there is no mention of a stack in their bible
Fact is, there isn't any C implementations that don't use
a stack to store the automatic variables.

Up to now, this people are unable to put forward a single
example of an implementation that doesn't use a hardware
stack (maintained by a register in a contiguous memory
addressing space)

Their first "example" was ARM and some Risc processors.

I proved them wrong.

Then they started tripping with IBM mainframes. Nope, I showed
them the documentation of the IBM compilers for mainframes
where they describe the stack and its associated register (r13)

Then they started with the 8051. I showed them that that processor
has a stack (it has PUSH/POP instructions apparently) but it is
too small, so some compilers use an external stack.

Even if they have not a single example, they go on with bullshit of the
style "but an implementation *could* exist that... blah blah blah"

Facts are not important. The C standard does not mention a stack,
and that is it. It is possible then to throw at unaware people that
asks questions in this group sentences like
"C has no stack"
"There is no stack in C"

Since they have no arguments, they discuss with tricks like

1) After you have proved them yet another time wrong, they will
answer with the eternal sentence "The standard doesn't mention a
stack" and the discussion can start from the beginning

2) After you have proved that the machine XYZ DOES have a stack,
they say "But an implementation *could* exist" and the discussion
can start from the beginning.

I decided that it is a waste of time to discuss with them. They just
repeat their bullshit without caring about what you answer to them

Personally I will not answer any more to falcolner and co. "C has no
stack" for them? Let it be.

You might think that things like recursion force a stack into existence.
They do not.

Furthermore, a stack in a machine is a very outdated creature.

When you brought this up before, I retreated to texts, and I don't think
your stack has any more "stackness" than

int i=42;
int j=46;

I believe the notion is abstract. Like a binary sort.
 
U

user923005

You're insanely obsessed about this stack thing.


If you use ``stack'' to refer to anything in C, that is wrong, since
whatever you are giving that name to doesn't precisely coincide with
the stack.

C has automatic storage, whose concept more broadly encompasses the
state of the data processor. In actual implementations, automatic
storage is implemented not only using the stack but also other storage
areas such as registers, or even immediate operands within the machine
code.

A statement like ``the function arguments are stored in the stack'' is
only correct if ``stack'' is redefined as a synonym for ``automatic
storage'', which is a bad idea, since you need that word to refer to
the machine-specific structure.

That isn't always true either. The Microsoft C compiler and the Intel
C compiler will allow you to pass arguments as registers instead of
autos.
It's a terrible idea to take a word with an existing meaning and then
redefine it to have another meaning for something that is closely-
related. Even worse is to then use the two meanings interchangeably in
the same context.


So that's what, ten paragraphs of letting it be? Good grief.

Bottom line:
1. C does not require a stack.
2. Almost all C compilers will have a stack implemented somewhere,
somehow.
3. If there was ever a tempest in a teapot, it quibbling about the
existence of a stack in C.

The OP {in the other thread} wanted to know why stacks are used at
all. They are simple to use and it can be faster than allocated
memory. But the down-side is that it is possible to put too much data
on the stack and if you exceed the size of a stack, and that may be
hard to diagnose.

Someone else said that it is useful to understand a stack when you are
debugging. Again, this has truth to it. But the meaning of 'you have
overflowed the stack' {which cannot be defined in terms of the C
standard} and 'you have exhausted automatic memory' {which can be
understood purely in terms of the C standard} are the same (as far as
a C implementation that pushes arguments onto a stack when making
function calls, for instance). And as for particulars about dealing
with stack overflow, I suspect that a compiler specific web site or
news forum would be far better than bringing it up here.

So where are we then? I guess right back where we started.
 
S

stop

You're insanely obsessed about this stack thing.


If you use ``stack'' to refer to anything in C, that is wrong, since
whatever you are giving that name to doesn't precisely coincide with
the stack.

C has automatic storage, whose concept more broadly encompasses the
state of the data processor. In actual implementations, automatic
storage is implemented not only using the stack but also other storage
areas such as registers, or even immediate operands within the machine
code.

A statement like ``the function arguments are stored in the stack'' is
only correct if ``stack'' is redefined as a synonym for ``automatic
storage'', which is a bad idea, since you need that word to refer to
the machine-specific structure.

That isn't always true either. The Microsoft C compiler and the Intel
C compiler will allow you to pass arguments as registers instead of
autos.
It's a terrible idea to take a word with an existing meaning and then
redefine it to have another meaning for something that is closely-
related. Even worse is to then use the two meanings interchangeably in
the same context.


So that's what, ten paragraphs of letting it be? Good grief.

Bottom line:
1. C does not require a stack.
It's not just C. I'd bet dollars to donuts that c++ and fortran don't as
well. I've never laid eyes on anything that purports to be standardesque in
c++, so I couldn't be sure.

What I know of it, they leave it to implementation. There's nothing that a
stack does that can't be replictaed through a non-stack method. I have it
from Richard Maine on this.

A stack, like a binary search tree, is important to the business of
programming but not treated in the standards. With all of the headaches
that attend already to standards, I wouldn't be for adding differing stack
notions to them.
 
K

Keith Thompson

user923005 said:
That isn't always true either. The Microsoft C compiler and the Intel
C compiler will allow you to pass arguments as registers instead of
autos.

Yes, it is always true. Parameters are objects with automatic storage
duration. Objects with automatic storage duration may be stored in
registers.

I agree. Unfortunately, we're stuck with two different firmly
entrenced meanings of the word "stack".
Even worse is to then use the two meanings interchangeably in
the same context.
Agreed.

[...]

Bottom line:
1. C does not require a stack.

C does not require a contiguous hardware stack. It does require a
LIFO mechanism of some sort, which is also called a "stack". Please
do not ignore this important distinction.

[...]
 
K

Kenny McCormack

Keith Thompson said:
C does not require a contiguous hardware stack. It does require a
LIFO mechanism of some sort, which is also called a "stack". Please
do not ignore this important distinction.

Oh oh. You're in trouble now.

According to the real zealots (*), C does not require anything (LIFO
mechanism or anything like that), as long as it behaves "as if" it did.

(*) A group in which I always thought you were counted.
 
U

user923005

That isn't always true either.  The Microsoft C compiler and the Intel
C compiler will allow you to pass arguments as registers instead of
autos.

Yes, it is always true.  Parameters are objects with automatic storage
duration.  Objects with automatic storage duration may be stored in
registers.

I agree.  Unfortunately, we're stuck with two different firmly
entrenced meanings of the word "stack".
         Even worse is to then use the two meanings interchangeably in
the same context.
Agreed.

[...]

Bottom line:
1.  C does not require a stack.

C does not require a contiguous hardware stack.  It does require a
LIFO mechanism of some sort, which is also called a "stack".  Please
do not ignore this important distinction.

Is it possible to store the parameters, call addresses and automatic
variables in a hash table or other random access list?
Is there a formal requirement that (for instance) the first parameter
is removed, and then the second and then the third?
If so, it does not require a stack at all. It only requires some sort
of storage mechanism that allows you to create things, find them, and
delete them.

I'm not convinced.
 
P

Peter Nilsson

user923005 said:
Is it possible to store the parameters, call addresses
and automatic variables in a hash table or other random
access list?
Is there a formal requirement that (for instance) the
first parameter is removed, and then the second and then
the third?
If so, it does not require a stack at all.  It only
requires some sort of storage mechanism that allows you
to create things, find them, and delete them.

I'm not convinced.

In the absense of recursive functions, no stack (real
or abstract) is required. However, in the presence of
recursion a stack like data structure is required.
 
M

Morris Dovey

Peter said:
In the absense of recursive functions, no stack (real
or abstract) is required. However, in the presence of
recursion a stack like data structure is required.

Peter...

I don't understand. If none is required for ordinary functions,
why is one required for recursive functions? How does a
self-invocation differ from invocation of some other function?
 
U

user923005

In the absense of recursive functions, no stack (real
or abstract) is required. However, in the presence of
recursion a stack like data structure is required.

void foo(int a)
{
int b;
if (condition_not_met()) foo(a);
}

assembly skeleton pseudocode:

void foo(int a)
{
allocate b and store it in a hash table...
call condition_not_met() test function
if return is true{
allocate a copy of a and put it in a hash table. Give this copy to
new foo() call
find copy of a in hash table
remove a from hash table
}
...
remove b from hash table
}

This is not a stack (and just to be contrary, I will remove items
stored a,b,c in order a,b,c instead of b,c,a when I exit). It will
run on a machine without a hardware stack or a software stack.
Logically, it produces the same result as using a stack would.
 
K

Keith Thompson

user923005 said:
Is it possible to store the parameters, call addresses and automatic
variables in a hash table or other random access list?
Yes.

Is there a formal requirement that (for instance) the first parameter
is removed, and then the second and then the third?
No.

If so, it does not require a stack at all. It only requires some sort
of storage mechanism that allows you to create things, find them, and
delete them.

I'm not convinced.

The fact that C's requirements imply some sort of LIFO mechanism (a
"stack" in the abstract computer science sense of the word), that
doesn't say anything about the order of allocation of the parameters
in a given function call, or of the local variables (formally, objects
with automatic storage duration) within a function or block.

The lifetimes of the automatic objects in a program are logically
nested. There's no ordering requirement for objects within a single
scope, but there are requirements *across* scopes.

Suppose func1 calls func2, which calls func3. Anything local to func3
has a lifetime that's a strict subset of the lifetime of anything
local to func2, which in turn is a strict subset of the lifetime of
anything local to func1.

The unit of allocation in this implied LIFO scheme is not a single
object; it's the set of objects at a given scope.

There are, of course, variations in how these lifetimes are
implemented. Implementations aren't *required* to deallocate objects
when their lifetimes end (and many don't bother to do so when the
lifetime is the duration of a nested block). But they are required to
behave *as if* automatic objects with nested lifetimes are created and
destroyed in a LIFO fashion, as far as any strictly conforming program
can tell.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,019
Latest member
RoxannaSta

Latest Threads

Top