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.