question on static variable in a function

  • Thread starter subramanian100in
  • Start date
S

subramanian100in

In the following link,
http://www.c-faq.com/malloc/retaggr.html

The following ANSWER is given to a question(comp.lang.c FAQ list ·
Question 7.5a) :

Whenever a function returns a pointer, make sure that the pointed-to
memory is properly allocated. For example, make sure you have not done
something like

#include <stdio.h>

char *itoa(int n)
{
char retbuf[20]; /* WRONG */
sprintf(retbuf, "%d", n);
return retbuf; /* WRONG */
}

When a function returns, its automatic, local variables are discarded,
so the returned pointer in this case is invalid (it points to an array
that no longer exists).

One fix would be to declare the return buffer as

static char retbuf[20];

This fix is imperfect, since a function using static data is not
reentrant.

My question is what "reentrant" means here? Why is static data inside
function discouraged ?
 
K

Kenny McCormack

When a function returns, its automatic, local variables are discarded,
so the returned pointer in this case is invalid (it points to an array
that no longer exists).

One fix would be to declare the return buffer as

static char retbuf[20];

This fix is imperfect, since a function using static data is not
reentrant.

My question is what "reentrant" means here? Why is static data inside
function discouraged ?

There are at least 3 things that can go wrong using this approach:
1) The primary import of the phrase "not reentrant" is that it
can't be used in a multi-threaded application. I.e., in a
multi-thread, there could be more than one active
invocation of the function.
2) Functions with static data cannot be called recursively.
3) The following code, although not involving either recursion
or threading, doesn't work as expected:

char *a,*b;
a = afunc(someparams);
b = afunc(someparams);
/* Do something with a & b */

It is actually #3 above that's the most annoying (IMHO).
 
B

Ben Pfaff

static char retbuf[20];

This fix is imperfect, since a function using static data is not
reentrant.

My question is what "reentrant" means here? Why is static data inside
function discouraged ?

If you call the function twice, then the answer you get on the
second call will replace the answer you get on the first call.
Unless you make a copy of the value returned the first time, or
you don't need to refer to it after the second call, this can be
very surprising.

This is not, strictly speaking, what "reentrant" is generally
taken to mean, but it is the problem that you will encounter in
this situation.
 
S

subramanian100in

I understand your points 1) and 3). But I have used static integer
counter variable in a recursive method which works.

I cannot understand the reason as to why recursive function
cannot contain static data.
 
B

bluejack

My question is what "reentrant" means here? Why is static data inside
function discouraged ?

Specifically, "reentrant" means that an application can re-enter the
function while already executing the function, whether by recursion or
in the execution of a different thread. This makes sense, right?
Since static data persists across multiple executions of a function,
if one line of execution is using that data and another modifies it,
you are almost certainly going to encounter problems.

Nor can variables declared static be relied upon to act as thread
control flags (unless they are part of some well-crafted thread
library that will very likely use implementation specific resources to
guarantee thread safety). The following, for example, cannot be relied
upon to work correctly:

void do_some_multithreaded_work(char* param) {
static int active = 0;

try_again:
if (active) {
goto try_again;
} else {
active = 1;
/* do something to param */
active = 0;
}
}

Why? Because two threads could be so close together, that both would
pass the "if (active)" test before either set active to 1. If you were
trying to protect this because both threads might be working on the
same character string pointed to by param, then you could have both
threads acting on param at the same time, which is probably not what
you want. Ok, not a *great* example, but you get the point, I hope.

Recursion is a little different. A static int might be useful for
counting your recursion depth, for example:

void recursive_func(void) {
static int depth = 0;
depth++;
if (depth > 10) return;
recursive_func();
}

Ok, possibly an even worse example, if you think about it a little,
but you see how the depth counter would work?

What you wouldn't want in a recursive function would be static data
that participates in the work of the function that calls itself (or
can be called lower in the call chain from within this function).
Sure, there are exceptions, but in general, you're asking for trouble.

Data that is static within a function is a lot like an old fashioned
global variable: it has many of the same drawbacks, and thus is
generally discouraged. It doesn't have global scope, it can't be used
willy nilly from everywhere, but as it spans both time and multiple
lines of execution, it's a hazard.

-Bluejack
 
L

Lew Pitcher

In the following link,http://www.c-faq.com/malloc/retaggr.html

The following ANSWER is given to a question(comp.lang.c FAQ list ·
Question 7.5a) :

Whenever a function returns a pointer, make sure that the pointed-to
memory is properly allocated. [snip]
When a function returns, its automatic, local variables are discarded,
so the returned pointer in this case is invalid (it points to an array
that no longer exists).

One fix would be to declare the return buffer as

static char retbuf[20];

This fix is imperfect, since a function using static data is not
reentrant.

My question is what "reentrant" means here? Why is static data inside
function discouraged ?

Consider the following code fragments...

#include <stdio.h>

char *foo(int bar)
{
char baz[256];

sprintf(baz,"%d",bar);
return baz;
}

void somefunc(void)
{
printf("%s, %s\n",foo(10),foo(-999));
}

What will printf() in somefunc() print?
Why?
 
C

Chris Dollin

Kenny said:
2) Functions with static data cannot be called recursively.

I don't think that's what you mean to say, since they
can, and further the effect of having a static can
be useful. (Apart from scoping issues, it's the same
as having the static outside the function, of course.)
 
L

Lew Pitcher

A minor correction

The following ANSWER is given to a question(comp.lang.c FAQ list ·
Question 7.5a) :
Whenever a function returns a pointer, make sure that the pointed-to
memory is properly allocated. [snip]
When a function returns, its automatic, local variables are discarded,
so the returned pointer in this case is invalid (it points to an array
that no longer exists).
One fix would be to declare the return buffer as
static char retbuf[20];
This fix is imperfect, since a function using static data is not
reentrant.
My question is what "reentrant" means here? Why is static data inside
function discouraged ?

Consider the following code fragments...

#include <stdio.h>

char *foo(int bar)
{
char baz[256];
Make that

static char baz[256];

Sorry :-S
 
M

Mark McIntyre

On 6 Mar 2007 06:17:46 -0800, in comp.lang.c ,
"(e-mail address removed), India" <[email protected]>
wrote:

(of static local variables and their unsuitability )
My question is what "reentrant" means here? Why is static data inside
function discouraged ?

If you call the function in several different threads, or call it
recursively, or call it twice in a function argument list, you may get
peculiar answers, or even possibly a crash.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
K

Kenny McCormack

I don't think that's what you mean to say, since they
can, and further the effect of having a static can
be useful. (Apart from scoping issues, it's the same
as having the static outside the function, of course.)

Others have addressed this. Short answer: Yes, I did mean it, but I
didn't go through all the necessary hoops to make it nitpick-proof.

Among others, Mark McI says:

If you call the function in several different threads, or call it
*recursively* (emphasis mine, Ed.) , or call it twice in a function
argument list, you may get peculiar answers, or even possibly a crash.
 
C

CBFalconer

I understand your points 1) and 3). But I have used static integer
counter variable in a recursive method which works.

I cannot understand the reason as to why recursive function
cannot contain static data.

It can if you only call it once from outside, or if you don't use
the variable. I can think of other limited scenarios.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
R

Richard Tobin

If you call the function in several different threads, or call it
recursively, or call it twice in a function argument list, you may get
peculiar answers, or even possibly a crash.

Isn't it guaranteed that function calls in an argument list are called
without overlap?

-- Richard
 
M

Mark McIntyre

Isn't it guaranteed that function calls in an argument list are called
without overlap?

AFAIR the order in which they're evaluated is unspecified, so I
believe that

f1(f2(3), f2(2)) ;

might result in either f2(2) or f2(3) being evaluated first, or even
possibly both at once. I could probably construct a pathological
example of where this would matter but its not hard ot think of one.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
R

Richard Tobin

Isn't it guaranteed that function calls in an argument list are called
without overlap?
[/QUOTE]
AFAIR the order in which they're evaluated is unspecified, so I
believe that

f1(f2(3), f2(2)) ;

might result in either f2(2) or f2(3) being evaluated first,
Yes.

or even possibly both at once.

Surely no, because there is a sequence point before each of the
functions is called.

-- Richard
 
D

Dave Vandervies

AFAIR the order in which they're evaluated is unspecified, so I
believe that

f1(f2(3), f2(2)) ;

might result in either f2(2) or f2(3) being evaluated first, or even
possibly both at once. I could probably construct a pathological
example of where this would matter but its not hard ot think of one.

I believe that there are sequence points around the actual function call,
which would force them to not be interleaved modulo the as-if rule.

I seem to recall somebody pointing out to me that that didn't apply to
evaluation of the arguments, though, so
f1(f2(f2_args),f3(f3_args));
could happen as:
--------
evaluate f2 arguments }
evaluate f3 arguments } May be interleaved
(Sequence point)
call f2 >
(Sequence point) > order not specified
call f3 >
(sequence point)
call f1
--------

So, f'rexample, something like:
--------
#include <stdio.h>
int foo(void)
{
static int i;
return i++;
}
int main(void)
{
printf("%d %d\n",foo(),foo());
return 0;
}
--------
doesn't invoke undefined behavior (it must print either "1 2\n" or
"2 1\n"), but this one:
--------
#include <stdio.h>
int foo(int i) { return i; }
int main(void)
{
int i=0;
printf("%d %d\n",foo(i++),foo(i++));
return 0;
}
--------
is allowed to cause a rhinodaemon infestation.


dave

--
Dave Vandervies (e-mail address removed)
your a morron.
Beautiful. Classic sig block material.
--Richard Heathfield roasts a troll in comp.lang.c
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,781
Messages
2,569,619
Members
45,316
Latest member
naturesElixirCBDGummies

Latest Threads

Top