dave@ur-helheim.UUCP (Sinse Raver Dave) (02/12/86)
In c one can declare variables within any {} block. Does a {} pair *imply* new context, with stack frame shifts, etc. I would have to assume so if local variables are declared within the {} but if no variables are declared? ... The reason for asking is for ease of expansion and consistancy of formatting I often put {} blocks where they are not necessary (clauses that are only one statement). Am I paying a penalty for these one-statement clauses or will my trusted compiler note the context has not changed and inhibit the subsequent costly stack manipulations? Mail or to the net any helpful ganders. (Not male geese.) dave -- "The Faster I Go the Behinder I Get" --Lewis Carroll Dave Carlson {allegra,seismo,decvax}!rochester!ur-valhalla!dave
ark@alice.UucP (Andrew Koenig) (02/14/86)
> In c one can declare variables within any {} block. Does a > {} pair *imply* new context, with stack frame shifts, etc. > I would have to assume so if local variables are declared > within the {} but if no variables are declared? ... The semantics are as if the {} allocated a new stack frame, but what actually happens is up to the compiler. Every compiler I have seen actually allocates stack memory only at entry to a procedure, both for greater speed and in order to do the right thing in case someone jumps into a "block".
mauney@ncsu.UUCP (Jon Mauney) (02/14/86)
> In c one can declare variables within any {} block. > ... > Am I paying a penalty for these one-statement clauses Block structure is static with respect to the enclosing procedure and can be taken care of by the compiler, with no run-time stack manipulations required. Any compiler that tries to be efficient should do this. Any compiler that has a run-time penalty for use of {} without local declarations should be shot. -- Jon Mauney, mcnc!ncsu!mauney North Carolina State University
gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/16/86)
In article <463@ur-helheim.UUCP> dave@ur-helheim.UUCP (Raver Dave) writes: > >In c one can declare variables within any {} block. Does a >{} pair *imply* new context, with stack frame shifts, etc. >I would have to assume so if local variables are declared >within the {} but if no variables are declared? ... > >The reason for asking is for ease of expansion and >consistancy of formatting I often put {} blocks where >they are not necessary (clauses that are only one >statement). Am I paying a penalty for these one-statement >clauses or will my trusted compiler note the context has >not changed and inhibit the subsequent costly stack manipulations? If your C compiler generates additional overhead for local blocks, it is not very good. Most reasonable implementations reserve enough stack at function entry for the deepest local block nesting within the function, so that there is no run-time action required upon entering a local block.
robison@uiucdcsb.CS.UIUC.EDU (02/17/86)
The output from C compilers I have seen indicates there is no penalty for {} blocks with declarations. All allocation can be done at the function entry. I.e., the source code: int f(x,y) int x,y; { int a,b; ... { int m,n; ... } ... } generates assembly code which allocates a,b,m, and n on the stack upon entry. The only difference between a,b and m,n is that m,n is visible only within the inner block. - Arch Robison
cottrell@NBS-VMS.ARPA (COTTRELL, JAMES) (02/19/86)
> In article <463@ur-helheim.UUCP> dave@ur-helheim.UUCP (Raver Dave) writes: > > > >In c one can declare variables within any {} block. Does a > >{} pair *imply* new context, with stack frame shifts, etc. > >I would have to assume so if local variables are declared > >within the {} but if no variables are declared? ... > > > >The reason for asking is for ease of expansion and > >consistancy of formatting I often put {} blocks where > >they are not necessary (clauses that are only one > >statement). Am I paying a penalty for these one-statement > >clauses or will my trusted compiler note the context has > >not changed and inhibit the subsequent costly stack manipulations? To which Dagwynn responds: > If your C compiler generates additional overhead for local > blocks, it is not very good. Most reasonable implementations > reserve enough stack at function entry for the deepest local > block nesting within the function, so that there is no > run-time action required upon entering a local block. Not only `not very good' but seemingly impossible. If a separate stack frame was created, access to arguments would be different within the new block. Still doable, but now try jumping in or out of the block. Getting Hairy! My experience is that the variable is allocated as if it were declared local to the funxion, but with it's scope restricted to the new block. Doug is correct. Fear not, it's cool. jim cottrell@nbs */ ------
ka@hropus.UUCP (Kenneth Almquist) (02/20/86)
>> If your C compiler generates additional overhead for local >> blocks, it is not very good. Most reasonable implementations >> reserve enough stack at function entry for the deepest local >> block nesting within the function, so that there is no >> run-time action required upon entering a local block. [DAGWYNN] > > Not only `not very good' but seemingly impossible. If a separate > stack frame [were] created, access to arguments would be different > within the new block. Still doable, but now try jumping in or > out of the block. Getting Hairy! [COTTRELL] There is at least one compiler out there for which does this. I know because I got a bug report on vnews concerning a piece of code where I jumped into the middle of a block. The rule is that the effect of jumping into a block containing declarations is machine dependent. All other jumps, such as jumping into a block that contains no variable declarations or jumping out of a block that does, are all legal, just as in PL/1. Cottrell overestimates the difficulty of allocating variables declared in a block when that block is entered. On a stack based machine, when you enter a block with declarations, the compiler merely adjusts the stack pointer to make room for the variables. When you exit the block, either by reaching the bottom or by doing a goto out of it, the stack pointer must be adjusted back. This is also fairly simple if the com- piler is prepared to read the entire routine before it starts generating code (otherwise it wouldn't know which goto's required adjustment to the stack pointer). Ideally, the compiler should also adjust the stack pointer when compiling a goto into a block that contains declarations, but C does not require this. The advantage of this approach is that stack space may be saved if subroutines are called outside the block. In most code the space savings won't make much difference. The disadvantage is the extra time spent adjusting the stack pointer. Again this cost is likely to be small, but my guess is that is the cost of adjusting the stack pointer will usually outweigh the space savings that it brings, and most compiler writers appear to agree. Still, you cannot count on this if you want to write portable code. Kenneth Almquist ihnp4!houxm!hropus!ka (official name) ihnp4!opus!ka (shorter path)
brooks@lll-crg.ARpA (Eugene D. Brooks III) (02/20/86)
The idea of creating a new context with each entry to a {} block, or at least for some very special ones, has some merit worth thinking about. Suppose you have extended C for parallel programming. main() { int i; int shared; forall(i from 0 to 9) { int private; /* lines of code */ } } if the forall loop is looked at as a fork of 10 lines of control which join up at the closing brace then the opening brace must do something special to the stack frame so that 10 seperate copies of 'private' are generated. The int 'shared' is on the stack of the parent and can be read or written by all of the lines of control but the stack splits into 10 segments at the opening brace of the forall loop.
rb@ccivax.UUCP (rex ballard) (02/20/86)
In article <139200021@uiucdcsb> robison@uiucdcsb.CS.UIUC.EDU writes: > >The output from C compilers I have seen indicates there is no penalty for >{} blocks with declarations. All allocation can be done at the function entry. >I.e., the source code: > > int f(x,y) > int x,y; > { > int a,b; > ... > { > int m,n; > ... > } > ... > } > >generates assembly code which allocates a,b,m, and n on the stack upon entry. >The only difference between a,b and m,n is that m,n is visible >only within the inner block. I know of two compilers, one for RT-11, that will allocate the additional stack space separately. A 'goto' in or out of an inner block will cause the stack space to be adjusted before the loop. This makes the parser simpler, but requires extra code. If no variables are declared, the block is transparent. Conditional blocks are better defined inside "allocation local blocks" in this case.
brett@wjvax.UUCP (Brett Galloway) (02/21/86)
This posting may be slightly inappropriate in net.lang.c, but I am interested
in the matter of how variables get declared in routine subblocks (i.e.
within {} within a routine; for example:
routine()
{ int a;
{ int b; }
}
I would assume that they are declared in routine()'s stack frame,
and that the only effect of declaring them in a subblock is to restrict
their scope to that subblock.
HOWEVER, in the Mt Xinu port of BSD 4.2 (for a VAX 750), dbx does not seem to
treat them this way; once dbx has moved into a subblock in which variables
are declared, any variables higher up in the stack are marked as
"not active". This behaviour of dbx appears to be wrong. My question is
whether this behaviour is simply a shortcoming of dbx's implementation of
subblock scoping, or whether it reflects some peculiarity in the way
variables declared in subblocks are treated by the c compiler.
My apologies if this question is obvious or inappropriate. Please send me
mail if the answer is not of general interest.
-------------
Brett Galloway
{pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett
davidsen@steinmetz.UUCP (Davidsen) (02/27/86)
In article <289@hropus.UUCP> ka@hropus.UUCP (Kenneth Almquist) writes: >>> If your C compiler generates additional overhead for local >>> blocks, it is not very good. Most reasonable implementations >>> reserve enough stack at function entry for the deepest local >>> block nesting within the function, so that there is no >>> run-time action required upon entering a local block. [DAGWYNN] >> >> Not only `not very good' but seemingly impossible. If a separate >> stack frame [were] created, access to arguments would be different >> within the new block. Still doable, but now try jumping in or >> out of the block. Getting Hairy! [COTTRELL] > >There is at least one compiler out there for which does this. I know >because I got a bug report on vnews concerning a piece of code where >I jumped into the middle of a block. ... On machines which do not have stack hardware, C may be implemented by using offsets to a register, since all offsets can be calculated at compile time. I first saw this in the "B" compiler for GE600 (Honeywell 6000/DPS) systems in about 1970. On entry to a procedure a register pointed to the return, arguments were offsets in one direction, and local variables were offsets in the other. The allocation consisted of assuming a larger number for "bytes in use" when entering the inner block. There is nothing faster at runtime than an assumption made at compile time... no code, no overhead. Point of allocation becomes important when variables are initialized, since in C it happens when the space is allocated (by this I mean that static variables are allocated at link time and initialized then, once, while auto variables are allocated and initialized on entry to a block. If the variables are allocated on entry to the procedure (which means that all inner block variables are taking stack space at once), the code to initialize them still has to be at the head of the inner block. Allocating inner block variables at procedure entry will save space/time on many machines, while allocating them at block entry will save stack space. -- -bill davidsen seismo!rochester!steinmetz!--\ / \ ihnp4! unirot ------------->---> crdos1!davidsen \ / chinet! ---------------------/ (davidsen@ge-crd.ARPA) "It seemed like a good idea at the time..."
cottrell@NBS-VMS.ARPA (COTTRELL, JAMES) (02/28/86)
/* > >> If your C compiler generates additional overhead for local > >> blocks, it is not very good. Most reasonable implementations > >> reserve enough stack at function entry for the deepest local > >> block nesting within the function, so that there is no > >> run-time action required upon entering a local block. [DAGWYNN] > > > > Not only `not very good' but seemingly impossible. If a separate > > stack frame [were] created, access to arguments would be different > > within the new block. Still doable, but now try jumping in or > > out of the block. Getting Hairy! [COTTRELL] > > There is at least one compiler out there for which does this. I know > because I got a bug report on vnews concerning a piece of code where > I jumped into the middle of a block. The rule is that the effect of > jumping into a block containing declarations is machine dependent. All > other jumps, such as jumping into a block that contains no variable > declarations or jumping out of a block that does, are all legal, just > as in PL/1. While I rarely do this (I did for the Rand editor for the arrow keys, they had `ESC [ A', & my terminal produced both that & `ESC O A' as well. I jumped from one switch into the other) I would not expect any penalty by doing this. I consider the idea of blocks stupid, merely syntactic sugar. `{' is `then'. `}' is `end'. Functions should be small enuf so that nested blocks are not needed. But I'm rambling... > Cottrell overestimates the difficulty of allocating variables declared > in a block when that block is entered. On a stack based machine, when > you enter a block with declarations, the compiler merely adjusts the > stack pointer to make room for the variables. And I think you underestimate the difficulty. You are not creating a new stack frame, which is what the original discussion mentioned. Also, are you referencing your variables relative to the stack pointer, or the frame pointer? The stack pointer moves around, especially in expressions like: `{ int q = 3; printf("%d%d%d%d\n",q,q*q,q*q*q,q*q*q*q); }'. >When you exit the block, > either by reaching the bottom or by doing a goto out of it, the stack > pointer must be adjusted back. This is also fairly simple if the com- > piler is prepared to read the entire routine before it starts generating > code (otherwise it wouldn't know which goto's required adjustment to the > stack pointer). Ideally, the compiler should also adjust the stack > pointer when compiling a goto into a block that contains declarations, > but C does not require this. While all this is possible, the way Doug described is so much simpler, faster, easier, & offers less surprises. Your compiler must have been written by a nested block freak. > The advantage of this approach is that stack space may be saved if > subroutines are called outside the block. In most code the space > savings won't make much difference. The disadvantage is the extra time > spent adjusting the stack pointer. Again this cost is likely to be small, > but my guess is that is the cost of adjusting the stack pointer will > usually outweigh the space savings that it brings, and most compiler > writers appear to agree. Still, you cannot count on this if you want > to write portable code. I agree totally. If it's small, who cares. If it's big, use malloc. The time overhead is the same to adjust the stack pointer by one as it is to adjust it by one thousand. Unless you have an `add quick'. > Kenneth Almquist > ihnp4!houxm!hropus!ka (official name) > ihnp4!opus!ka (shorter path) jim cottrell@nbs */ ------