By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
431,899 Members | 1,066 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 431,899 IT Pros & Developers. It's quick & easy.

allocation of local variables on stack

P: n/a
Hi,

When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations? Is a function activation record supposed to be
fixed before you start executing the function code (i.e. statements)?

If this is done at run-time, how does the (standard) compiler do it?

I have also heard about an alloca() call for allocating on the stack.
Is this a non-standard function? Is there a possibility of stack
overflow by doing this?

Thanks,
Bahadir

Nov 14 '05 #1
Share this Question
Share on Google+
26 Replies


P: n/a


ba************@gmail.com wrote:
Hi,

When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations?
They are allocated whenever (and wherever) the compiler
chooses. Different compilers will use different strategies;
a single compiler may use different strategies depending on
the rest of the code.
Is a function activation record supposed to be
fixed before you start executing the function code (i.e. statements)?
C does not have a "function activation record." While
a function is executing there is enough information stored
somewhere to allow it to return to its caller and perhaps to
return a value, but that's about all one can say. Again, it's
the compiler's choice about how to maintain this information,
and different compilers will do it differently.
If this is done at run-time, how does the (standard) compiler do it?
I'm not sure what you're asking -- but in any case, there
is no one standard compiler, no "reference implementation." The
language definition describes the effect of running a valid program,
but not how that effect is achieved. Almost all such matters are
left to the discretion of the implementors, so they can have the
freedom to exploit the special characteristics of the platform.
I have also heard about an alloca() call for allocating on the stack.
Is this a non-standard function? Is there a possibility of stack
overflow by doing this?


See Question 7.32 in the comp.lang.c Frequently Asked
Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html

--
Er*********@sun.com

Nov 14 '05 #2

P: n/a
In article <11**********************@g44g2000cwa.googlegroups .com>,
<ba************@gmail.com> wrote:

When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations?


It's better to program as if you didn't know or care, and in
a lot of cases simple variables like that won't even be
on the stack. They'll be optimized away or placed in registers.

With that out of the way, in my observations of a several
different machines, the stack is usually allocated all-at-once
upon entry to the function. There can be overlap though:

void func()
{
int a;

{
int b;
}
{
int c;
}
}

b and c may share a memory location, and that shared b+c memory
location is probably "allocated" on the "stack" at the same
time as a. I use scare quotes because these are implementation-specific
concepts that aren't part of C proper.

About the only time I think any of these issues would be
externally visible would be if a recursive function
used an excessive amount of stack space in a nested
statement, but the recursion occured outside of that.
Consider this incomplete code:

int func(int a)
{
if (a > 0)
{
/* non-trivial return (usually) prevents tail-recursion elimination */
return other_func(a) * func(a-1);
}
else
{
struct gigantic_struct foo[1000000];
/* perform non-trivial processing of gigantic struct array */
/* return non-trivial value after processing */
}
}

Unless the compiler was particularly clever, it might grow
the stack at an alarming rate. I'll have to try this
one out with my favorite compilers and see what happens.
--
7842++
Nov 14 '05 #3

P: n/a
Anonymous 7843 wrote:
In article <11**********************@g44g2000cwa.googlegroups .com>,
<ba************@gmail.com> wrote:

When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations?


It's better to program as if you didn't know or care, and in
a lot of cases simple variables like that won't even be
on the stack. They'll be optimized away or placed in registers.

With that out of the way, in my observations of a several
different machines, the stack is usually allocated all-at-once
upon entry to the function. There can be overlap though:

void func()
{
int a;

{
int b;
}
{
int c;
}
}

b and c may share a memory location, and that shared b+c memory
location is probably "allocated" on the "stack" at the same
time as a. I use scare quotes because these are implementation-specific
concepts that aren't part of C proper.

About the only time I think any of these issues would be
externally visible would be if a recursive function
used an excessive amount of stack space in a nested
statement, but the recursion occured outside of that.
Consider this incomplete code:

int func(int a)
{
if (a > 0)
{
/* non-trivial return (usually) prevents tail-recursion elimination */
return other_func(a) * func(a-1);
}
else
{
struct gigantic_struct foo[1000000];
/* perform non-trivial processing of gigantic struct array */
/* return non-trivial value after processing */
}
}

Unless the compiler was particularly clever, it might grow
the stack at an alarming rate. I'll have to try this
one out with my favorite compilers and see what happens.
--
7842++


Thanks a lot, your explanation was very helpful. I asked this because I
was also wondering what would happen when a similar situation as you
exemplified would occur. But yours emphasised it better.

I personally care for these things even if you save an array or two at
runtime. It doesn't make a big difference but it doesn't hurt to code
knowing about it. It may even help in limited stack situations.

Thanks,
Bahadir

Nov 14 '05 #4

P: n/a

Le 14/06/2005 18:51, dans
11**********************@g44g2000cwa.googlegroups. com,
«*ba************@gmail.com*» <ba************@gmail.com> a écrit*:
Hi,

When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations? Is a function activation record supposed to be
fixed before you start executing the function code (i.e. statements)?
As already stated, it's implementation dependent. On MacOSX/PowerPC, the
stack is fixed at the beginning of the function, and is not easily
changed afterwards: there is a 24 byte block at the end of the stack frame,
used by any called function. I haven't checked but probably alloca needs to
change this block. On Wintel on the other hand, the stack may be expanded
at any time.

Another interesting point (MacOSX): when a function is called, parameters
are passed by register and if needed on the caller's stack frame, so when
a function is entered, enough space must be reserved in its stack frame
for any function it calls, even if it actually don't call any: the compiler
cannot know that. And of course the stack frame must contain space for
all local variables. This makes a rather big stack frame :-)

If this is done at run-time, how does the (standard) compiler do it?

I have also heard about an alloca() call for allocating on the stack.
Is this a non-standard function? Is there a possibility of stack
overflow by doing this?

Thanks,
Bahadir


Nov 14 '05 #5

P: n/a
ba************@gmail.com wrote:
Anonymous 7843 wrote:
<ba************@gmail.com> wrote:

When you define varibles in the middle of your function call
(C99), such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at
run-time or are they allocated before, along with the
arguments and initial variable declarations?
It's better to program as if you didn't know or care, and in
a lot of cases simple variables like that won't even be
on the stack. They'll be optimized away or placed in registers.

With that out of the way, in my observations of a several
different machines, the stack is usually allocated all-at-once
upon entry to the function. There can be overlap though:

void func() { /* EDITED for compression cbf */
int a;
{ int b; }
{ int c; }
}

b and c may share a memory location, and that shared b+c memory
location is probably "allocated" on the "stack" at the same
time as a. I use scare quotes because these are implementation-
specific concepts that aren't part of C proper.

.... snip ...
Thanks a lot, your explanation was very helpful. I asked this
because I was also wondering what would happen when a similar
situation as you exemplified would occur. But yours emphasised it
better.

I personally care for these things even if you save an array or
two at runtime. It doesn't make a big difference but it doesn't
hurt to code knowing about it. It may even help in limited stack
situations.


I'm leaping in here for two reasons. One is that you are a google
user who is using the system correctly, with adequate quotes etc.
So it IS possible. Congratulations, and it shows that we should
not automatically killfile all google users.

The other is the generic problem of off-topicness. This whole
thread is off-topic, yet where is the newbie to go? [1] We who
have been around for <mumble> [2] years have a pretty good idea of
how things are implemented, or have done the implementation. As a
result we have a fair idea of why the standard imposes, or doesn't
impose, things in various areas. This knowledge is not system or
language or machine specific until it is applied to one specific
situation. One example is stacks. The IBM 360 family doesn't have
them. Yet it can implement automatic storage. Almost everything
that grew out of the PDP11, VAX, x86, 68xxx, etc. has stack
capabilities.

There was a time when all programming, to all practical purposes,
was done in assembly. As languages and their implementations
improved assembly grew less and less important, EXCEPT to the
implementors. Nowadays we can even restrict that EXCEPT to the
implementors of the final code generators. But the assembly
features are built to facilitate the high level language
implementation, and the implementations are skewed to use the
existing machine features, etc. There is no really sharp
demarcation point. We're here because there's beer because we're
here.

I've been around here for a while, so I'll probably get away with
this without excessive bitching. You, on the other hand, would
most likely have been yelled at for a similar post. And that may
be quite proper, in that I think I have demonstrated that I have a
fairly good idea of what I am talking about, and you haven't. As
yet. In time, you may.

[1] Not comp.programming, that deals with algorithms etc. Not
comp.os.*, those deal with particular systems. Not
comp.compilers.*, because the users need the knowledge. We need
comp.misc. Maybe it exists? But even if it does, it probably
doesn't have much traffic.

[2] <grumble>

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

Nov 14 '05 #6

P: n/a
Anonymous 7843 wrote:
In article <11**********************@g44g2000cwa.googlegroups .com>,
<ba************@gmail.com> wrote:
When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations?

It's better to program as if you didn't know or care, and in
a lot of cases simple variables like that won't even be
on the stack. They'll be optimized away or placed in registers.

With that out of the way, in my observations of a several
different machines, the stack is usually allocated all-at-once
upon entry to the function. There can be overlap though:

void func()
{
int a;

{
int b;
}
{
int c;
}
}

b and c may share a memory location, and that shared b+c memory
location is probably "allocated" on the "stack" at the same
time as a. I use scare quotes because these are implementation-specific
concepts that aren't part of C proper.

About the only time I think any of these issues would be
externally visible would be if a recursive function
used an excessive amount of stack space in a nested
statement, but the recursion occured outside of that.
Consider this incomplete code:

....

Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:

char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];

while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}

alloca(i);

char *buf = malloc(i);
memcpy(buf, myarray, i);
return buf;
}

Portability is all well and good, but i just wouldn't want to use a machine
that has no storage as easy to use as a stack. Without the stack, you'd have
to use expensive reallocs.
Nov 14 '05 #7

P: n/a
Russell Shaw wrote:
Anonymous 7843 wrote:
In article <11**********************@g44g2000cwa.googlegroups .com>,
<ba************@gmail.com> wrote:
When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations?
It's better to program as if you didn't know or care, and in
a lot of cases simple variables like that won't even be
on the stack. They'll be optimized away or placed in registers.

With that out of the way, in my observations of a several
different machines, the stack is usually allocated all-at-once upon
entry to the function. There can be overlap though:

void func()
{
int a;
{
int b;
}
{
int c;
}
}

b and c may share a memory location, and that shared b+c memory
location is probably "allocated" on the "stack" at the same
time as a. I use scare quotes because these are implementation-specific
concepts that aren't part of C proper.

About the only time I think any of these issues would be
externally visible would be if a recursive function
used an excessive amount of stack space in a nested
statement, but the recursion occured outside of that.
Consider this incomplete code:


...

Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:

char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];

while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}

alloca(i);

char *buf = malloc(i);


Correction:
memcpy(buf, myarray, i);
memcpy(buf, myarray + i + 1, myarray);
return buf;
}

Portability is all well and good, but i just wouldn't want to use a machine
that has no storage as easy to use as a stack. Without the stack, you'd
have
to use expensive reallocs.

Nov 14 '05 #8

P: n/a
Russell Shaw wrote:
Anonymous 7843 wrote:
In article <11**********************@g44g2000cwa.googlegroups .com>,
<ba************@gmail.com> wrote:
When you define varibles in the middle of your function call (C99),
such as:

if(i == 5) {
int x = 5;
int z = 2;
}

Are they allocated on the stack as they're encountered at run-time or
are they allocated before, along with the arguments and initial
variable declarations?
It's better to program as if you didn't know or care, and in
a lot of cases simple variables like that won't even be
on the stack. They'll be optimized away or placed in registers.

With that out of the way, in my observations of a several
different machines, the stack is usually allocated all-at-once upon
entry to the function. There can be overlap though:

void func()
{
int a;
{
int b;
}
{
int c;
}
}

b and c may share a memory location, and that shared b+c memory
location is probably "allocated" on the "stack" at the same
time as a. I use scare quotes because these are implementation-specific
concepts that aren't part of C proper.

About the only time I think any of these issues would be
externally visible would be if a recursive function
used an excessive amount of stack space in a nested
statement, but the recursion occured outside of that.
Consider this incomplete code:


...

Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:

char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];

while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}

alloca(i);

char *buf = malloc(i);


Correction(2):
memcpy(buf, myarray, i);
memcpy(buf, myarray + i + 1, i);
return buf;
}

Portability is all well and good, but i just wouldn't want to use a machine
that has no storage as easy to use as a stack. Without the stack, you'd
have
to use expensive reallocs.

Nov 14 '05 #9

P: n/a
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:
[...]
Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:

char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];

while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}

alloca(i);

char *buf = malloc(i);
memcpy(buf, myarray, i);
return buf;
}

Portability is all well and good, but i just wouldn't want to use a machine
that has no storage as easy to use as a stack. Without the stack, you'd have
to use expensive reallocs.


Sorry, but that's just ugly. Apart from the misuse of feof() (you
should be checking whether fgetc() returned EOF), and the constraint
violation of declaring a zero-length array, you're assuming that the
space beyond myarray is "above" the top of the stack. Even assuming a
stack-based implementation, I can imagine the unallocated space you're
using being clobbered by an interrupt. (I don't even want to think
about what might happen in a multi-threading environment.)

There are functions available that will read a line of arbitrary
length from an input file, allocating it on the heap and expanding
with realloc() as necessary. If can be done portably, there's no
need, and no excuse, for code like the above.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #10

P: n/a
Keith Thompson wrote:
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:
[...]
Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:

char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];

while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}

alloca(i);

char *buf = malloc(i);
memcpy(buf, myarray, i);
return buf;
}

Portability is all well and good, but i just wouldn't want to use a machine
that has no storage as easy to use as a stack. Without the stack, you'd have
to use expensive reallocs.


Sorry, but that's just ugly. Apart from the misuse of feof() (you
should be checking whether fgetc() returned EOF), and the constraint
violation of declaring a zero-length array, you're assuming that the
space beyond myarray is "above" the top of the stack. Even assuming a
stack-based implementation, I can imagine the unallocated space you're
using being clobbered by an interrupt. (I don't even want to think
about what might happen in a multi-threading environment.)

There are functions available that will read a line of arbitrary
length from an input file, allocating it on the heap and expanding
with realloc() as necessary. If can be done portably, there's no
need, and no excuse, for code like the above.


How about:

char* getfile(FILE *infile)
{
size_t i = 0;

while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}

char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}
Nov 14 '05 #11

P: n/a
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:
[...]
How about:

char* getfile(FILE *infile)
{
size_t i = 0;

while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}

char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}


Even funnier.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #12

P: n/a
Jean-Claude Arbaut <je****************@laposte.net> wrote:
Another interesting point (MacOSX): when a function is called, parameters
are passed by register and if needed on the caller's stack frame, so when
a function is entered, enough space must be reserved in its stack frame
for any function it calls, even if it actually don't call any: the compiler
cannot know that. And of course the stack frame must contain space for
all local variables. This makes a rather big stack frame :-)


C allows for (indirectly, so not necessarily detectably) recursive
function calls. Have fun trying to allocate an infinite stack frame.

Richard
Nov 14 '05 #13

P: n/a
Richard Bos wrote:
Jean-Claude Arbaut <je****************@laposte.net> wrote:

Another interesting point (MacOSX): when a function is called, parameters
are passed by register and if needed on the caller's stack frame, so when
a function is entered, enough space must be reserved in its stack frame
for any function it calls, even if it actually don't call any: the compiler
cannot know that. And of course the stack frame must contain space for
all local variables. This makes a rather big stack frame :-)


C allows for (indirectly, so not necessarily detectably) recursive
function calls. Have fun trying to allocate an infinite stack frame.

Richard


Stack usage is only infinite if the recursion never ends, which usually
means broken code. Anyway, you can always make sure tail-call optimization
is used in which case only the space of one frame is used.
Nov 14 '05 #14

P: n/a
Keith Thompson wrote:
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:
[...]
How about:

char* getfile(FILE *infile)
{
size_t i = 0;

while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}

char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}


Even funnier.


I always run stuff thru gdb unless it's posted here. Of course the stack
is unwound on exit from the local context;)

char* getfile(FILE *infile)
{
size_t i = 0;

while(1) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}
i++;
}
}

I more frequently return stuff directly on the stack than with
malloc.
Nov 14 '05 #15

P: n/a

Le 15/06/2005 08:27, dans ac************@main.anatron.com.au, «*Russell
Shaw*» <rjshawN_o@s_pam.netspace.net.au> a écrit*:
How about:

char* getfile(FILE *infile)
{
size_t i = 0;

while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}

char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}


It may work on your machine, as your preceding post, but
on any other, you have no guarantee alloca creates contiguous
blocks, and in correct order. Depending on your application,
it may or may not be a problem.

Another point: in your preceding post you use "myarray[i++]=..."
so the stack would be growing from low to high addresses, and
in the end you use memcpy with "myarray+i+1", why ?
In this post it's the opposite: if it works, ptr must be the
lower address of you "alloca-ted" block, so stack grows
from high addresses to low addresses.

And BTW, I would replace "while(!feof(infile))" with "for(;;)".

Not so ugly after all, but bear in mind it's highly non-portable.

Nov 14 '05 #16

P: n/a

Le 15/06/2005 10:19, dans 42****************@news.xs4all.nl, «*Richard Bos*»
<rl*@hoekstra-uitgeverij.nl> a écrit*:
Jean-Claude Arbaut <je****************@laposte.net> wrote:
Another interesting point (MacOSX): when a function is called, parameters
are passed by register and if needed on the caller's stack frame, so when
a function is entered, enough space must be reserved in its stack frame
for any function it calls, even if it actually don't call any: the compiler
cannot know that. And of course the stack frame must contain space for
all local variables. This makes a rather big stack frame :-)


C allows for (indirectly, so not necessarily detectably) recursive
function calls. Have fun trying to allocate an infinite stack frame.

Richard


Not infinite: one stack frame for each call. The total amount of stack used
is potentially infinite but function calls *are* finite, that's what
matters. And in case you're interested, stack may be up to 64MiB.

Nov 14 '05 #17

P: n/a
Jean-Claude Arbaut wrote:


Le 15/06/2005 08:27, dans ac************@main.anatron.com.au, « Russell
Shaw » <rjshawN_o@s_pam.netspace.net.au> a écrit :

How about:

char* getfile(FILE *infile)
{
size_t i = 0;

while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}

char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}

It may work on your machine, as your preceding post, but
on any other, you have no guarantee alloca creates contiguous
blocks, and in correct order. Depending on your application,
it may or may not be a problem.


man alloca (on linux) says it just moves the stack pointer.
The above function is garbage, which is usually the case
before i've tested it. ptr is declared inside the loop (should
be outside). And if(*ptr == EOF) is redundant (i was thinking of
if(*ptr == -1), but that doesn't happen for fgetc()).
Another point: in your preceding post you use "myarray[i++]=..."
so the stack would be growing from low to high addresses, and
in the end you use memcpy with "myarray+i+1", why ?
In this post it's the opposite: if it works, ptr must be the
lower address of you "alloca-ted" block, so stack grows
from high addresses to low addresses.
I got totally confused because i was doing things with alloca
in a memory allocator i wrote a week ago, that needed things
reversed because the stack grows downwards and the heap upwards.
The allocator works now, and does hierarchial garbage collection
(without using alloca).
And BTW, I would replace "while(!feof(infile))" with "for(;;)".

Not so ugly after all, but bear in mind it's highly non-portable.


Wasn't the best example.
Nov 14 '05 #18

P: n/a
Le 15/06/2005 13:07, dans 0p************@main.anatron.com.au, «*Russell
Shaw*» <rjshawN_o@s_pam.netspace.net.au> a écrit*:
man alloca (on linux) says it just moves the stack pointer.


On (your) Linux, probably. But there may be many things between the
stack pointer and your local variable, including other local variables,
(and maybe saved registers, or a block of special data needed for
stack mainenance) and it's not clear *where* alloca leaves space.
You can only refer to the address returned by alloca, but of course
if you know how it runs on your machine and don't care of portability,
it's perfect.

Nov 14 '05 #19

P: n/a
Russell Shaw wrote:

Keith Thompson wrote:
Even funnier.

char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {


If char is an unsigned type, then there's no way that
*ptr can equal EOF.

And I would just like to say that heaps and stacks
as they have been discussed in this thread,
have nothing to do with C are off topic for the newsgroup.

--
pete
Nov 14 '05 #20

P: n/a
Keith Thompson wrote:
.... snip ...
There are functions available that will read a line of arbitrary
length from an input file, allocating it on the heap and expanding
with realloc() as necessary. If can be done portably, there's no
need, and no excuse, for code like the above.


Such as my ggets, freely available at:

<http://cbfalconer.home.att.net/download/ggets.zip>

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #21

P: n/a
>> Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:
Sometimes you don't know how much data you're going to read, so you
just have to plonk stuff on the stack regardless:

char* getfile(FILE *infile)
{
size_t i = 0;
char myarray[0];

while(!feof(infile)) {
myarray[i++] = fgetc(infile);
}

alloca(i);

char *buf = malloc(i);
memcpy(buf, myarray, i);
return buf;
}
Keith Thompson wrote:
Sorry, but that's just ugly.

It is worse than that: it does not even work, crashing right after
reading sufficiently long lines (even when using gcc on Linux on
an i386).
Apart from the misuse of feof() ...


Indeed.

In article <ac************@main.anatron.com.au>,
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:How about:

char* getfile(FILE *infile)
{
size_t i = 0;

while(!feof(infile)) {
char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {
return NULL;
}
}

char *buf = malloc(i);
memcpy(buf, ptr, i);
return buf;
}

This one has the advantage of "almost working" on some machines.

It still behaves very oddly on a SPARC. (Try it! It breaks even
on a SPARC running Linux, using gcc.)

The reason is that alloca() on the SPARC rounds the size up to
the nearest multiple of 8, as required by the architecture. Each
alloca(1) -- sizeof(char) is necessarily 1 -- allocates 8 bytes.
The text winds up strangely spaced.

It also fails when run on a few other, in another peculiar way: it
adds a mysterious '\377' character to the file. The reason is that
fgetc(infile) returns EOF, which is stored in *ptr, which has
type (plain) char, which is unsigned char. The test *ptr==EOF
compares 255 against -1; they are not equal and we make one more
trip through the loop. This time, feof(infile) is true -- because
the last fgetc() failed due to EOF -- and we believe that the
file ended with a '\377' byte.

It also fails mysteriously (on those machines) when run with input
redirected to a file that is on a floppy with a bad sector. This
time, it loops forever. The reason is that, as before, fgetc()
returns EOF, which is stored in the plain (and thus unsigned)
"char", and then we compare 255 vs -1, so we continue to loop.
This time, however, feof(infile) is false, because the failure was
due to an I/O error rather than EOF.

There are a number of "morals of the story", as it were. The main
two are:

Never use feof(). (For the advanced C programmer: "Well, hardly
ever.")

Do not depend on undocumented "features" like alloca() returning
contiguous bytes, because these are not always true.

Of course, there is a way to do this without using alloca() at all,
so that the code will work on any system supporting C89 or C99; but
if the goal is "to use alloca()", using only the standard C89/C99
features will not suffice, since alloca() is not one of them. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #22

P: n/a
CBFalconer wrote:
I'm leaping in here for two reasons. One is that you are a google
user who is using the system correctly, with adequate quotes etc.
So it IS possible. Congratulations, and it shows that we should
not automatically killfile all google users.
Thanks.
The other is the generic problem of off-topicness. This whole
thread is off-topic, yet where is the newbie to go?


Sorry about this. To be honest, I enjoyed the stack discussion, but I
must admit I didn't think enough to realise stacks were off-topic
before posting. I know how ugly it is when you see irrelevant/newbie
questions - I won't do it again.

Thanks,
Bahadir

Nov 14 '05 #23

P: n/a
pete wrote:
Russell Shaw wrote:
Keith Thompson wrote:

Even funnier.

char *ptr = alloca(sizeof(char));
*ptr = fgetc(infile);
if(*ptr == EOF) {


If char is an unsigned type, then there's no way that
*ptr can equal EOF.


And if char is signed, then *ptr may equal EOF even though
the end of file has not been reached yet.

Also I don't see how the OP code could possibly work,
unless there's something about alloca nobody told me.
The next line of code was: memcpy(buf, ptr, i).

But ptr points to exactly one char, so if i>1 then he
is reading uninitialized memory. Also he has lost all
the chars he alloca'd in previous iterations of the loop.

Nov 14 '05 #24

P: n/a

Le 16/06/2005 00:58, dans
11**********************@z14g2000cwz.googlegroups. com, «*Old Wolf*»
<ol*****@inspire.net.nz> a écrit*:
Also I don't see how the OP code could possibly work,
unless there's something about alloca nobody told me.
Apart from the numerous bugs, it could actually work,
but it is *highly* system- and compiler- dependant.
(and no need to say, highly non-standard).

char *tmp;
char *ptr = alloca(sizeof(char));
int t;

for(;;) {
char *tmp = alloca(sizeof(char));
t = fgetc(infile);
*tmp = t;
if(*tmp == EOF) {
...
}
i++;
}

This will work if alloca allocates contiguous bytes
on the stack, and the final memcpy will work
dependind on which direction the stack grows.
If you try that, check asm output, because it's
very likely that the produced executable won't
do what you expect. And don't use that in
production code in any circumstances :-)
The next line of code was: memcpy(buf, ptr, i).
But ptr points to exactly one char, so if i>1 then he
is reading uninitialized memory. Also he has lost all
the chars he alloca'd in previous iterations of the loop.


We have lost nothing: previous chars were allocated
on the stack and initialized. We assume we know were
they actually are (just after the first char allocated).
Nov 14 '05 #25

P: n/a

In article <11**********************@g14g2000cwa.googlegroups .com>, ba************@gmail.com writes:
CBFalconer wrote:
The other is the generic problem of off-topicness. This whole
thread is off-topic, yet where is the newbie to go?
Sorry about this. To be honest, I enjoyed the stack discussion, but I
must admit I didn't think enough to realise stacks were off-topic
before posting.


IMO, the question as phrased was marginally on-topic, or perhaps just
the wrong side of topicality. There is to my mind a considerable
distance between "how are variables defined at inner scope allocated"
and, say, "how do I find out what's on my stack". The former is
something which conceivably might be (though in fact it is not)
covered by the standard, perhaps in some obscure fashion, while the
latter is clearly (to anyone who's taken a look at the standard
language features) implementation-specific.

Personally, I don't mind seeing questions about how language elements
are typically implemented, if they're posed well.

Another place for this sort of discussion is alt.folklore.computers,
where computing history is discussed. Unfortunately it's a relatively
high-volume group with a pronounced tendency to drift off-topic.
I know how ugly it is when you see irrelevant/newbie
questions - I won't do it again.


If all newbies were this careful with their posting style, I expect
there would be far less grumbling from the regulars.

--
Michael Wojcik mi************@microfocus.com

Thus, the black lie, issuing from his base throat, becomes a boomerang to
his hand, and he is hoist by his own petard, and finds himself a marked man.
-- attributed to a "small-town newspaper editor in Wisconsin"
Nov 14 '05 #26

P: n/a
In article <dnFre.230$X71.101@fed1read07>,
Anonymous 7843 <an******@example.com> wrote:

int func(int a)
{
if (a > 0)
{
/* non-trivial return (usually) prevents tail-recursion elimination */
return other_func(a) * func(a-1);
}
else
{
struct gigantic_struct foo[1000000];
/* perform non-trivial processing of gigantic struct array */
/* return non-trivial value after processing */
}
}

Unless the compiler was particularly clever, it might grow
the stack at an alarming rate. I'll have to try this
one out with my favorite compilers and see what happens.


I tried this on three high quality compilers with full
optimization enabled. They each ate up the whole stack
within a few iterations.

I won't name names since this is probably not a valuable
thing to optimize in C. I was just curious.
--
7842++
Nov 14 '05 #27

This discussion thread is closed

Replies have been disabled for this discussion.