[comp.lang.c] block variables

gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/18/87)

In article <102600020@datacube> ftw@datacube.UUCP writes:
>Space for "k" is alloctaed when the block under the "for" loop is entered,
>and de-allocated on the way out, rather than being re-allocated for each
>iteration of your loop.

Actually, most reasonable compilers allocate enough space for the
deepest contained block at entry to a function, then when execution
enters the block, the preallocated space is simply used without
having to perform any explicit allocation at that point.

rbutterworth@orchid.waterloo.edu (Ray Butterworth) (11/19/87)

In article <6692@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> Actually, most reasonable compilers allocate enough space for the
> deepest contained block at entry to a function, then when execution
> enters the block, the preallocated space is simply used without
> having to perform any explicit allocation at that point.

Don't you mean "UNreasonable"?
(or does "reasonable" refer to the fact that this is done by
some "infinite stack" C compilers, and you consider having an
infinite stack reasonable?)

Consider a recursive function:
    recurse(x)
    {
        auto int y;
        auto int z;
        {
            auto int temparray[10000];
            /*calculation of y and z using x*/
        }
        if (y) recurse(y);
        if (z) recurse(z);
    }

Admittedly it's not the most useful function in the world,
and the calculation could be moved to another function,
but a "reasonable" compiler would make the recursive call
only leaving enough room on the stack for the autos y and
z, and any overhead associated with making the call, say
a dozen bytes.  The compiler you describe (e.g. BSD 4.3)
would waste 40000 bytes for every level of recursion.
The "allocation" for each block could be done at compile
time, not at execution time, so there wouldn't be any loss
of cpu efficiency.


Besides, the "preallocate the most you'll ever need" approach
only encourages code such as this (excerpted from the BSD
source for VI):
    if (lhs[0] == '#') {
        char funkey[3];
        funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
        dname = funkey;
    }
    addmac(lhs,rhs,dname,mp);

On a different compiler, dname would be pointing at garbage
when addmac is called.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/20/87)

In article <11742@orchid.waterloo.edu> rbutterworth@orchid.waterloo.edu (Ray Butterworth) writes:
-In article <6692@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
-> Actually, most reasonable compilers allocate enough space for the
-> deepest contained block at entry to a function, then when execution
-> enters the block, the preallocated space is simply used without
-> having to perform any explicit allocation at that point.
-Don't you mean "UNreasonable"?
-(or does "reasonable" refer to the fact that this is done by
-some "infinite stack" C compilers, and you consider having an
-infinite stack reasonable?)
-Consider a recursive function:
-    recurse(x)
-    {
-        auto int y;
-        auto int z;
-        {
-            auto int temparray[10000];
-            /*calculation of y and z using x*/
-        }
-        if (y) recurse(y);
-        if (z) recurse(z);
-    }
-Admittedly it's not the most useful function in the world,
-and the calculation could be moved to another function,
-but a "reasonable" compiler would make the recursive call
-only leaving enough room on the stack for the autos y and
-z, and any overhead associated with making the call, say
-a dozen bytes.

This is not precluded by the behavior I described as "reasonable".
I don't think many compilers actually do that, but if they can
manage it it's a good trick.

By the way, you have trouble with large stack allocations like
this even without deep recursion.  Somebody porting my directory
access routines to a "large model" IBM PC implementation found
that his stack wasn't big enough for a 4Kb or so buffer.  Gould
UTX-32 has a fixed stack determined at link time, typically just
a few Kb.  For maximum portability, code should really use static
or explicit heap allocation for large structures and not rely on
the stack discipline to provide enough room.

-Besides, the "preallocate the most you'll ever need" approach
-only encourages code such as this (excerpted from the BSD
-source for VI):
-    if (lhs[0] == '#') {
-        char funkey[3];
-        funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
-        dname = funkey;
-    }
-    addmac(lhs,rhs,dname,mp);

That's erroneous code on any implementation; it just happens to
work for a handful of particular compiler implementations (much
as dereferencing a null pointer just happens to work for some
VAX C implementations).  I don't think it's relevant to the
discussion.