[comp.lang.c] Declaration within a loop.

dvu@prism.gatech.EDU (Dinh Vu) (09/27/89)

Declaration within a loop:
-------------------------

     do {
		 int i;

		 ........ ;
		 ........ ;
		 ........ ;

     } while (1);

Is it true that every time through the loop, a new i variable
is declared (more memory allocated ??)?  Or the same i variable
is reused...  I see something similiar to this in the GNU 'make' 
source code.  Also, if I run the code above long enough, will it 
take all memory.  Thanks.


Dinh Vu <dvu@prism.gatech.edu>

barmar@kulla (Barry Margolin) (09/27/89)

In article <2085@hydra.gatech.EDU> dvu@prism.gatech.EDU (Dinh Vu) writes:
>     do {
>		 int i;
>		 ........ ;
>     } while (1);
>Is it true that every time through the loop, a new i variable
>is declared (more memory allocated ??)?  

Yes, a new i variable is declared.  However, at the end of each time
through the loop it is "undeclared", so it can be deallocated.  Most C
implementations will actually use the same memory location (probably
on the stack) each time.  And since C isn't required to zero automatic
variables, it will probably even have the same value as it had in the
previous iteration; however, any program that tries to take advantage
of this is pretty disgusting, in my opinion.
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/27/89)

In article <30174@news.Think.COM>, barmar@kulla (Barry Margolin) writes:

|  Yes, a new i variable is declared.  However, at the end of each time
|  through the loop it is "undeclared", so it can be deallocated.  Most C
|  implementations will actually use the same memory location (probably
|  on the stack) each time. 

  Most C compilers allocate space on the stack for this when the
procedure is entered. It therefore is not a practical thing to do to
save space. The most common use is to correct for having forgotten to
declare a variable at the start of a procedure.
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

cpcahil@virtech.UUCP (Conor P. Cahill) (09/27/89)

In article <2085@hydra.gatech.EDU>, dvu@prism.gatech.EDU (Dinh Vu) writes:
> Is it true that every time through the loop, a new i variable
> is declared (more memory allocated ??)?  Or the same i variable
> is reused...  I see something similiar to this in the GNU 'make' 
> source code.  Also, if I run the code above long enough, will it 
> take all memory.  Thanks.

The variable i is an automatic variable allocated on the stack at the
start of block.  It is not re-allocated each time through the loop. 
This kind of thing can be verified by creating a small source code file
and compiling it with the -S flag to get the assembly language.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

cpcahil@virtech.UUCP (Conor P. Cahill) (09/27/89)

In article <30174@news.Think.COM>, barmar@kulla (Barry Margolin) writes:
> In article <2085@hydra.gatech.EDU> dvu@prism.gatech.EDU (Dinh Vu) writes:
> >     do {
> >		 int i;
> >		 ........ ;
> >     } while (1);
> >Is it true that every time through the loop, a new i variable
> >is declared (more memory allocated ??)?  
> 
> Yes, a new i variable is declared.  However, at the end of each time
> through the loop it is "undeclared", so it can be deallocated.  Most C

I disagree.  Using the following source code:

int main()
{
	int fd;
	char *p;
	char t;
	extern char *ttyname();

	int i;

	for(i=0; i < 10; i++)
	{
	    	char buffer[50];

		printf("buffer = 0x%x\n",buffer);
	}
}

The following assembly code is generated (using "cc" on 386/ix):

	.globl	main
main:
	jmp	.L54
.L53:
	movl	$0,-16(%ebp)			/* i = 0 */
	jmp	.L58
.L59:
	leal	-66(%ebp),%eax			/* get address of buffer */
	pushl	%eax				/* put on stack for printf */
	pushl	$.L60				/* put string on stack	*/
	call	printf				/* call printf		*/
	addl	$8,%esp				/* clean stack		*/
	incl	-16(%ebp)			/* i++			*/
.L58:
	movl	$10,%eax			/* get 10 for comparison*/
	cmpl	%eax,-16(%ebp)			/* compare i to 10	*/
	jl	.L59				/* I < 10 ?		*/
.L57:
.L52:
	leave
	ret
.L54:
	pushl	%ebp
	movl	%esp,%ebp
	subl	$68,%esp		
	jmp	.L53
	.def	main;	.val	.;	.scl	-1;	.endef
	.data
.L60:
	.byte	0x62,0x75,0x66,0x66,0x65,0x72,0x20,0x3d,0x20,0x30
	.byte	0x78,0x25,0x78,0x0a,0x00


Note that at .L54 the data is allocated ONCE and only once.  It is not 
allocated/deallocated for each iteration.  This is unoptimized assembler
source generated using the -S flag.


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

tneff@bfmny0.UU.NET (Tom Neff) (09/27/89)

In article <559@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
>  Most C compilers allocate space on the stack for this when the
>procedure is entered.  It therefore is not a practical thing to do to
>save space. 

For what it's worth AT&T's pcc on V/386 does share reuse stack space
among all temp in-block variables.  Intel's C compiler does not though.
I'm sure there are tons of other examples pro and con.

>             The most common use is to correct for having forgotten to
>declare a variable at the start of a procedure.

Here I must disagree.  The most common and obvious use of an in-block
temp is to restrict scope!  Unless one's editor lacks a "move up"
command there is no reason to declare a variable locally within a block
just because one "forgot" to declare it function-wide!  The declaration
is as easily added in one place as the other.  But it may be quite
important to ensure that "i" or "swaptmp" is unheard-of outside the
local block.
-- 
Annex Canada now!  Free Quebec; raze and depopulate  |  Tom Neff
Ontario; license Inuit-run casinos on the BC shore.  |  tneff@bfmny0.UU.NET

tim@cayman.amd.com (Tim Olson) (09/28/89)

In article <559@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
| In article <30174@news.Think.COM>, barmar@kulla (Barry Margolin) writes:
| 
| |  Yes, a new i variable is declared.  However, at the end of each time
| |  through the loop it is "undeclared", so it can be deallocated.  Most C
| |  implementations will actually use the same memory location (probably
| |  on the stack) each time. 
| 
|   Most C compilers allocate space on the stack for this when the
| procedure is entered. It therefore is not a practical thing to do to
| save space. The most common use is to correct for having forgotten to
| declare a variable at the start of a procedure.

But sometimes it is better to declare the variable in the block to
limit its scope rather than to make every variable visible to the
entire function.  For example, say I want to debug a function by
printing out a linked list at a certain point.  I can say something
like:

	.
	.
#ifdef DEBUG
	{
		struct list *p;
		for (p=my_list; p; p=p->next)
		    printf("\t%d\n",p->value);
        }
#endif

and I have limited my changes to one area.


	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

scott@bbxsda.UUCP (Scott Amspoker) (09/28/89)

In article <14743@bfmny0.UU.NET> tneff@bfmny0.UU.NET (Tom Neff) writes:
>For what it's worth AT&T's pcc on V/386 does share reuse stack space
>among all temp in-block variables.  Intel's C compiler does not though.
>I'm sure there are tons of other examples pro and con.
>

This is frequently poorly implmented.  I use local variables
in procedures mainly to save a little stack space (although
I don't do it very often).  In the following example:

proc()
   {
   if (...)
      {
      int i;
      ...
      }
   while (...)
      {
      int j;
      ...
      }
   }

the variables 'i' and 'j' may use the same location on the stack
frame.  Of course, this is a trivial example.  Some compilers, however,
simply give all local variables their own location.  I don't understand
that kind of laziness.

-- 
Scott Amspoker
Basis International, Albuquerque, NM
(505) 345-5232

djones@megatest.UUCP (Dave Jones) (09/28/89)

From article <27519@amdcad.AMD.COM>, by tim@cayman.amd.com (Tim Olson):
...
> 
> But sometimes it is better to declare the variable in the block to
> limit its scope rather than to make every variable visible to the
> entire function.


Why did you not say, "Always it is better to declare..."?

The only reason I can think of not to put variables into the most
restrictive scope that will contain them is that dbx has a bug that
causes it to give wrong results without complaint or warning if you use
the same name in two scopes.

There's nothing more sickening than to be confronted by an enemy procedure
with a skillion variables declared at the top.  Usually they have
generic names like, "temp1", and "ptr".

Well okay, maybe there's one thing more sickening than that, but I don't
see any reason to bring Jerry Lewis into this.

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/28/89)

cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>This kind of thing can be verified by creating a small source code file
>and compiling it with the -S flag to get the assembly language.

This statement is blatantly false (about anything about C).  It confuses
implementation with definition.  To re-use the same variable cell each time
through the loop is a valid implementation of deallocating it and reallocating
it each time through the loop, because deallocating and allocating are inverse
operations.  This doesn't mean that the meaning of declaring a variable inside
a loop in C is that it is allocated upon function entry.

ajr

cpcahil@virtech.UUCP (Conor P. Cahill) (09/28/89)

In article <559@crdos1.crd.ge.COM>, davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) writes:
>   Most C compilers allocate space on the stack for this when the
> procedure is entered. It therefore is not a practical thing to do to
> save space. The most common use is to correct for having forgotten to
> declare a variable at the start of a procedure.


There are two reasons that I will normally use for justifying variable
declarations and neither of them are to save space.

The first is #define macros. For example:

	#define	DEBUG(key,msg) {char buf[512];.... }

The second is to try to segregate the use of register variables.  I'm not
too sure this really has an effect in all compilers, but at least it gives
it a chance.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

cpcahil@virtech.UUCP (Conor P. Cahill) (09/28/89)

In article <1989Sep27.185904.18985@jarvis.csri.toronto.edu>, flaps@dgp.toronto.edu (Alan J Rosenthal) writes:
> This statement is blatantly false (about anything about C).  It confuses
> implementation with definition.  To re-use the same variable cell each time
> through the loop is a valid implementation of deallocating it and reallocating
> it each time through the loop, because deallocating and allocating are inverse
> operations.  This doesn't mean that the meaning of declaring a variable inside
> a loop in C is that it is allocated upon function entry.

I did not say that a variable declared within a loop is allocated upon 
function entry.  I said that it is not re-allocated throughout every iteration
of the loop.  The variable is "active" throughout the entire lifetime of the 
loop.  However, if the variable is initialized, it will be reinitialized 
each time through the loop.

In thinking about it a bit more since my original response I would have
to say that while this may be the behavior in any "sane" implementation,
it would not be prudent to have any expectations as to the value stored 
in the data area through each iteration of the loop.
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

plim@hpsgpa.HP.COM (Peter Lim) (09/28/89)

/ hpsgpa:comp.lang.c / tim@cayman.amd.com (Tim Olson) /  3:11 am  Sep 28, 1989 /

> But sometimes it is better to declare the variable in the block to
> limit its scope rather than to make every variable visible to the
> entire function.  For example, say I want to debug a function by
> printing out a linked list at a certain point.  I can say something
> like:
> 

Well, why don't you do something like adding an extra pair of braces
before and after the loop like:

  {
  int i;
     do {
       .
       .
     } while (1);
  }

this should limit the scope of i in the loop and clear the ambiguity
of whether i is re-allocated every time round the loop.
** Seem obvious to me.


Regards,
Peter Lim.
HP Singapore IC Design Center.

seanf@sco.COM (Sean Fagan) (09/29/89)

In article <1199@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>> Yes, a new i variable is declared.  However, at the end of each time
>> through the loop it is "undeclared", so it can be deallocated.  Most C
>
>I disagree.  Using the following source code:

You are also wrong.  Since you felt like posting source code, I think I will
do the same.  What do you expect the following code to do, when compiled and
run?

	static int x = 0;
	int foo() { return x++; }

	main() {
		int a;
		for (a=0; a< 100; a++)
		{
			int b = foo();
			printf ("b = %d\n", b);
		}
		return (0);
	}

If 'b' is not created each time, then foo() is only called once.  However,
you will note that it *isn't* called just once.

To explain (sort of) the results you got:  in the following fragment,

	for (a=0; a< 100; a++)
	{
		int b;
	}
	for (a=0; a< 200; a++)
	{
		int c;
	}

would you be surprised if &b == &c?  I wouldn't; and, in your example,
that's what was happening.  The compiler knew it could reuse the space, and
did so.  Did so so well, in fact, that it never touched the stack pointer
in-between the loops.

Anyway, that's what dmr says, so it must be right 8-).

-- 
Sean Eric Fagan  | "Time has little to do with infinity and jelly donuts."
seanf@sco.COM    |    -- Thomas Magnum (Tom Selleck), _Magnum, P.I._
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/29/89)

In article <3362@scolex.sco.COM>, seanf@sco.COM (Sean Fagan) writes:


|  	main() {
|  		int a;
|  		for (a=0; a< 100; a++)
|  		{
|  			int b = foo();
|  			printf ("b = %d\n", b);
|  		}
|  		return (0);
|  	}
|  
|  If 'b' is not created each time, then foo() is only called once.  However,
|  you will note that it *isn't* called just once.

  This is logical, but wrong. You are guaranteed that foo() will be
called each time through the loop, and that b will be initiallized, but
it is an implementation choice if some explicit action which could be
identified as "creating" b will be done each time or once.

  In most existing C compilers (I don't claim all) any explicit action
needed is taken once on entry to the procedure. As long as
initialization is done each time you can't tell from program behavior if
the allocation is done once or many time (not do I see any reason to care).
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon