Richard Heathfield said:
Keith Thompson said:
No, it doesn't. All auto objects defined within a given block die at the
same time, and the Standard doesn't specify in which order they must be
killed. Neither does the Standard require that they be defined in any
particular order, provided the behaviour is correct. Thus, if the code
reads: int a; double b; then the Standard doesn't give two hoots about
which is allocated first. If it's int a = 5, b = a; that's a slightly
different matter, although not much.
Keith Thompson said "across function calls" not "within a block". The
implicit LIFO allocation is in the nesting of the lifetimes of auto
variables across a call:
void g(void) {
int a, b, c;
f(); /* all f's auto variables start life after a, b and c exist */
/* and they must end their life before any of a, b or c do */
}
As Keith pointed out, this can all be managed with a simple static
block for each function (as early FORTRAN compilers often used)
provided that no function call chain contain a cycle. Without that
assurance, some form of stacking is the obvious solution.
A hash table would do it. You certainly don't need a stack.
Yes, but again, the obvious solution is a hash table where collisions
are handled with a linked list so when g() calls f() which calls g()
the old bindings for a, b and c get "pushed".
Note that I say "obvious". I think it is possible to construct a
contrived but conforming implementation in which there is almost no
identifiable LIFO structure (it will still be there in ghostly
form due to the wording of the standard). I'll outline it for
variables in functions, but it needs to be extended to nested blocks
as well.
Every function starts with code that collects the time from a counter
(maybe click ticks). This value is concatenated with the variable
name to make a hash key. In g() above, an assignment 'a = 42;' will
lookup a@234 if the call to g started at cycle 234. Functions save
their return address in a special variable so, when g() calls f() at
cycle 336 a variable RETURN-FROM@336 holds the location in g() where
f() was called from, and all of f()'s auto variables will have the
form <name>@336.
A special variable (hash key), CURRENT-CALL-CYCLE, stores the cycle
the current call stated on. This means that to find a variable we
construct sprintf("%s@%d", var_name, lookup("CURRENT-CALL-CYCLE"))
and look that up.
So far, no LIFO in sight -- not even in the return addresses. But all
good things must come to an end. When the call to f() at cycle 336
returns, control is passed to the location in RETURN-FROM@336. There
the compiler had planted code to set CURRENT-CALL-CYCLE back to 234.
(This requires a writable code segment but, hey, we are in fantasy
land here so does it matter if we do that too? An extra variable can
avoid any writable code, but it make the LIFO nature of the storage
scheme more obvious so I've not used it.)
It is very hard to see the LIFO structure here. It *is* there, of
course, in the odd variable names and ever-changing numbers in the
code stream, but it is there only in a ghostly way. I doubt, though,
that anyone could call this a stack.