[comp.lang.c] doing nasty things with internal static variables

fontenot@rice.edu (Dwayne Jacques Fontenot) (03/20/91)

Hello,

I have found myself doing this because it works, but I am curious if it
is a common practice or if it is highly likely to get me into trouble:

char *foo()
{
  static char string[64];

  ...
  return(string);
}

I am concerned about this because though I know that that static variable
is guaranteed to always be there for the function containing it, it is
not really guaranteed to be there (in memory) at any other time
(correct me if I'm wrong).

I have used this on ANSI compilers on diverse architectures with no problems
yet, and it's just so damned *convenient*.

Thank you for your time,
Dwayne Fontenot (fontenot@comet.rice.edu)

c60b-1eq@e260-1c.berkeley.edu (Noam Mendelson) (03/20/91)

In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu (Dwayne Jacques Fontenot) writes:
>I have found myself doing this because it works, but I am curious if it
>is a common practice or if it is highly likely to get me into trouble:
>
>char *foo()
>{
>  static char string[64];
>
>  ...
>  return(string);
>}

This is fine.  Since the area of memory occupied by the variable string
is guaranteed not to be touched, you can assume that string will have
the same value until it is directly modified.  I, in fact, use this
construct all the time.  It is extremely convenient.

===============================================================
Noam Mendelson                       | "I haven't lost my mind,
c60b-1eq@web.Berkeley.EDU            |  it's backed up on tape
University of California at Berkeley |  somewhere."

torek@elf.ee.lbl.gov (Chris Torek) (03/21/91)

In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu
(Dwayne Jacques Fontenot) writes:
>  static char string[64];
>  ...
>  return(string);

>I am concerned about this because though I know that that static variable
>is guaranteed to always be there for the function containing it, it is
>not really guaranteed to be there (in memory) at any other time
>(correct me if I'm wrong).

Consider yourself corrected.

The *entire* difference between a local `static' and a local automatic
variable is that there is, at *all* times that the program runs, exactly
one instance of the `static', while there may be zero or more instances
of the automatic (and in fact the number of instances is exactly the
same as the number of times that automatic is in scope, i.e.,

	f(n) { int silly; if (n > 1) f(n - 1); }
	...
		f(50);

has 50 copies of `silly' floating around somewhere inside the machine%
at the deepest level of recursion).
-----
% That is, provided the optimizer has not deleted this unused variable.
  The variables are not necessarily `on a stack'; the machine may not
  even have `stacks'.  Stacks are simply a common implementation method.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

mercer@npdiss1.StPaul.NCR.COM (Dan Mercer) (03/21/91)

In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu (Dwayne Jacques Fontenot) writes:
:Hello,
:
:I have found myself doing this because it works, but I am curious if it
:is a common practice or if it is highly likely to get me into trouble:
:
:char *foo()
:{
:  static char string[64];
:
:  ...
:  return(string);
:}
:
:I am concerned about this because though I know that that static variable
:is guaranteed to always be there for the function containing it, it is
:not really guaranteed to be there (in memory) at any other time
:(correct me if I'm wrong).
:
You are wrong.  There,  I corrected you.  Seriously,  there are,  in
general,  three places to keep variable data - the stack,  the heap,
and the static data area.  Automatic variable data is kept on the
stack.  It will always be there while you remain in the function,  but
is lost when the function exits and the stack is returned.  It is
lost,  not destroyed.  Many a fine bug has occurred because someone
returned the address of an automatic variable which is still correct
and accessible until some other function is called and uses the stack
area.

You use malloc to access the heap.

The static data area contains your constant data,  static data,  and
global data.  The only real difference (in the box) between static and
global data is that the linker knows how to access the global data.

:I have used this on ANSI compilers on diverse architectures with no problems
:yet, and it's just so damned *convenient*.
:
:Thank you for your time,
:Dwayne Fontenot (fontenot@comet.rice.edu)


-- 
Dan Mercer
NCR Network Products Division      -        Network Integration Services
Reply-To: mercer@npdiss1.StPaul.NCR.COM (Dan Mercer)
"MAN - the ultimate one word oxymoron in the English Language"

gwyn@smoke.brl.mil (Doug Gwyn) (03/21/91)

In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu (Dwayne Jacques Fontenot) writes:
-char *foo()
-{
-  static char string[64];
-  ...
-  return(string);
-}
-I am concerned about this because though I know that that static variable
-is guaranteed to always be there for the function containing it, it is
-not really guaranteed to be there (in memory) at any other time
-(correct me if I'm wrong).

There's nothing particularly wrong with that usage.  Objects having
static storage duration exist throughout program execution.  Now, if
you had omitted the "static" storage-class specifier, the array would
have been an automatic variable, and auto storage does "evaporate"
upon leaving the block in which it is declared.

browns@iccgcc.decnet.ab.com (Stan Brown) (03/22/91)

In article <1991Mar19.183920.18911@rice.edu>, fontenot@rice.edu (Dwayne Jacques Fontenot) writes:
> I have found myself doing this because it works, but I am curious if it
> is a common practice or if it is highly likely to get me into trouble:
> 
> char *foo()
> {
>   static char string[64];
>   ...
>   return(string);
> }
> 
> I am concerned about this because though I know that that static variable
> is guaranteed to always be there for the function containing it, it is
> not really guaranteed to be there (in memory) at any other time
> (correct me if I'm wrong).

This is one time where you might be glad to be wrong.

Any variable declared as static is guaranteed to stay around for the
entire execution of the program.

BTW, the parentheses in your return statement are not necessary.

My opinions are mine:  I don't speak for any other person or company.
                   email (until 91/4/30): browns@iccgcc.decnet.ab.com
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA    +1 216 371 0043

f90angu@fy.chalmers.se (Andreas Gunnarsson) (03/22/91)

In article <15526@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu (Dwayne Jacques Fontenot) writes:
>-char *foo()
>-{
>-  static char string[64];
>-  ...
>-  return(string);
>-}
>-I am concerned about this because though I know that that static variable
>-is guaranteed to always be there for the function containing it, it is
>-not really guaranteed to be there (in memory) at any other time
>-(correct me if I'm wrong).
>
>There's nothing particularly wrong with that usage.  Objects having
>static storage duration exist throughout program execution.  Now, if
>you had omitted the "static" storage-class specifier, the array would
>have been an automatic variable, and auto storage does "evaporate"
>upon leaving the block in which it is declared.

Are you sure? On virtual memory machines you're probably right, but in
overlayed programs - does C really guarantee that the pointer always is valid?
Then that means that no static data will be overlayed? At least not if a
pointer to it could be returned to the caller (via return or arguments
(possibly via other assigns inside the function)).
If I'd need to pass a pointer to static data back, I'd define it as a global
variable instead of local. I think it looks ugly, but since I'm not sure it'll
work with the next compiler i wouldn't take the chance.
-- 
==============================================================================
73 es 88 de SM7TLS          f90angu@fy.chalmers.se          Andreas Gunnarsson
==============================================================================

lamont@uts.amdahl.com (Duane Richard LaMont) (03/22/91)

In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu (Dwayne Jacques Fontenot) writes:
>I have found myself doing this because it works, but I am curious if it
>is a common practice or if it is highly likely to get me into trouble:
>
>char *foo()
>{
>  static char string[64];
>
>  ...
>  return(string);
>}

Thus far, the followups to the posting above have focused on the fact
that this method works and is common practice, etc.  However, I would
like to point out one caveat which I've experienced.

I once wrote a function like foo which returned different strings based
on the value of a lone argument.  One of my less experienced co-workers
attempted to use it and did something like this:

    char *a, *b;

    a = foo(x);
    b = foo(y);
    printf("a = %s; b = %s\n", a, b);

Much to her surprise, string a was always identical to string b
regardless of the values of x and y.  I pointed out that a and
b both pointed to the static buffer within foo which was overwritten
on each call.  So, I was feeling pretty good about myself until the
next week when I wrote something like this:

    bar(foo(x), foo(y));

My new rule of thumb: If the higher level application programmer
is likely to call my function multiple times and save the results
separately, make him pass in his own buffer.  This saves him
from making calls to strcpy.

Also note that, at least on my system, asctime uses a static return
buffer and has this caveat listed on the man page.

Rick LaMont

torek@elf.ee.lbl.gov (Chris Torek) (03/22/91)

In article <1991Mar22.013548.29788@fy.chalmers.se>
f90angu@fy.chalmers.se (Andreas Gunnarsson) writes:
>Are you sure? On virtual memory machines you're probably right, but in
>overlayed programs - does C really guarantee that the pointer [to
>a local static] always is valid?

Yes.

>Then that means that no static data will be overlayed? At least not if a
>pointer to it could be returned to the caller (via return or arguments
>(possibly via other assigns inside the function)).

Another alternative is `fat pointers': every pointer carries with it an
`overlay' number.  If the pointer points into a currently-unloaded data
section, that section must be loaded (somewhere).

If the pointers are built from <overlay, offset> pairs, this
essentially amounts to simulating hardware paging (as appears on most
modern CPUs) in software.

The guarantee is that, to a C programmer who `obeys all the rules',
static storage is always present.  There is no way to tell whether
it `disappears' for a while, or appears spontaneously the first time
it is used, without `cheating' (using machine-dependent code).
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

d9erikb@dtek.chalmers.se (Erik Bergersjo) (03/22/91)

In article <1991Mar22.013548.29788@fy.chalmers.se> f90angu@fy.chalmers.se
(Andreas Gunnarsson) writes:

>In article <15526@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>>In article <1991Mar19.183920.18911@rice.edu> fontenot@comet.rice.edu
>>(Dwayne Jacques Fontenot) writes:
>>-char *foo()
>>-{
>>-  static char string[64];
>>-  ...
>>-  return(string);
>>-}
>>
>>There's nothing particularly wrong with that usage.  Objects having
>>static storage duration exist throughout program execution.
>
>Are you sure? On virtual memory machines you're probably right, but in
>overlayed programs - does C really guarantee that the pointer always is valid?
>Then that means that no static data will be overlayed?

I don't know if the pointer is guaranteed to be valid on all systems.
However, I do know how static variables are handled on my system
(Amiga 500 - no virtual memory, Lattice C) and I think it's done in a
similar way on other machines, too. (I'd like to know if I'm wrong!)

Static variables are placed in special hunks with the hunkname "__MERGED"
in the objectfiles. At link time, all hunks with this name are - as the
name implies - merged. The resulting hunk is put into the root node.
In other words, no static data will be overlayed and a pointer to a
static variable will always be valid, even when overlays are used.
                                             . .
				Erik Bergersj o
				d9erikb@dtek.chalmers.se

gwyn@smoke.brl.mil (Doug Gwyn) (03/23/91)

In article <1991Mar22.013548.29788@fy.chalmers.se> f90angu@fy.chalmers.se (Andreas Gunnarsson) writes:
>Are you sure?

Yes.

bhoughto@pima.intel.com (Blair P. Houghton) (03/23/91)

In article <78hW01XR47Gy00@amdahl.uts.amdahl.com> lamont@amdahl.uts.amdahl.com (Duane Richard LaMont) writes:
>Much to her surprise, string a was always identical to string b
>regardless of the values of x and y.  I pointed out that a and
>b both pointed to the static buffer within foo which was overwritten
>on each call.  So, I was feeling pretty good about myself until the
>next week when I wrote something like this:

Why would you feel good about yourself?  She had to
search out the author rather than find the answer
in the documentation.  Did you update the docs?
That'd be something to be happy about.

>Also note that, at least on my system, asctime uses a static return
>buffer and has this caveat listed on the man page.

strtok(3) also makes much noise about its using
static space to store the token-string.

The converse of this situation is a function that operates
on the string pointed to by something you passed it, then
returns a pointer back to you that presumably points to the
result of the operation, when the result of the operation
is that your string's been munged.  Most of the <string.h>
stuff does this (so does strtok(3), actually, so it gets
you both coming and going).

				--Blair
				  "Kinda like when you think all
				   you did was post an example..."