![]() |
why does this work ?
Why does f get returned ? (compiled with gcc).
#include<stdio.h> int func(int a); main() { int f; f=func(7); printf("f=%d",f); } int func(int a) { int f,d = 100; if (a<10){ f = d; } } Ta, Bamber. |
Re: why does this work ?
Bamber <bamber_gascoigne2001@yahoo.co.uk> scribbled the following:
> Why does f get returned ? (compiled with gcc). It doesn't. You're mistaking implementation-dependent behaviour for normal operation. > #include<stdio.h> > int func(int a); > main() > { int f; > f=func(7); > printf("f=%d",f); > > } > int func(int a) > { > int f,d = 100; > if (a<10){ > f = d; > } > } When control reaches the end of func(), the returned value is indeterminate. When the assignment f=func(7) is done in main(), the C implementation tries to get a value from where there isn't any. On some implementations, this is the last value put on a stack before the assignment happens, but there is no requirement that implementations should do this. There is no requirement for implementations to *have* a stack in the first place. Generally, you just got (un)lucky. -- /-- Joona Palaste (palaste@cc.helsinki.fi) ---------------------------\ | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++| | http://www.helsinki.fi/~palaste W++ B OP+ | \----------------------------------------- Finland rules! ------------/ "Ice cream sales somehow cause drownings: both happen in summer." - Antti Voipio & Arto Wikla |
Re: why does this work ?
Greetings.
In article <37011f05.0310100303.45464bcd@posting.google.com >, Bamber wrote: > Why does f get returned ? It doesn't. In fact, nothing gets returned, since there is no return statement to be found anywhere in your program. Regards, Tristan -- _ _V.-o Tristan Miller [en,(fr,de,ia)] >< Space is limited / |`-' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-= <> In a haiku, so it's hard (7_\\ http://www.nothingisreal.com/ >< To finish what you |
Re: why does this work ?
In <37011f05.0310100303.45464bcd@posting.google.com > bamber_gascoigne2001@yahoo.co.uk (Bamber) writes:
>Why does f get returned ? (compiled with gcc). > >#include<stdio.h> > >int func(int a); > >main() >{ int f; > f=func(7); > printf("f=%d",f); There is a newline character missing in this format string. > >} >int func(int a) >{ > int f,d = 100; > if (a<10){ > f = d; > } >} By pure accident. Your code invokes undefined behaviour, by using the value returned by a function that doesn't actually return anything, so *anything* can happen. Compiled with the same compiler, on a diferent platform, the output is different: mentor:~/tmp 11> uname -a SunOS mentor 5.8 Generic_108528-11 sun4u sparc mentor:~/tmp 12> cat test.c #include<stdio.h> int func(int a); main() { int f; f=func(7); printf("f=%d\n",f); } int func(int a) { int f,d = 100; if (a<10){ f = d; } } mentor:~/tmp 13> gcc test.c mentor:~/tmp 14> ./a.out f=7 This doesn't look like f's value before func() returns, does it? By your logic, I should start asking myself: why does func() return the value of its parameter? ;-) Moral: it is a pure waste of time to try to understand why a piece of broken code behaves the way it does. Dan -- Dan Pop DESY Zeuthen, RZ group Email: Dan.Pop@ifh.de |
Re: why does this work ?
Joona I Palaste wrote:
> <snip> > There is no requirement for implementations to *have* a stack in the first place. This is the second time I see this posted over the last couple of days, and you're surely right. But it does beg the following question: ---- #include <stdio.h> /* returns n! modulo 2^(number of bits in an unsigned long) */ unsigned long f(unsigned long n) { return (n==0) ? 1 : f(n-1)*n; } int main(void) { unsigned long z; for(z=1;z!=0;z*=2) { printf("%lu %lu\n", z, f(z)); fflush(stdout); } return 0; } ---- As far as I can see, this is a perfectly valid C program that should reach the 'return 0' statement always, were it not for the fact that in all compilers I tried (one, actually) it terminates with a segmentation fault of some sort, due to limited stack size. Is this 'incorrect behavior' of all these compilers, or is there some wording in the Standard that covers for machines with a finite stack (much to my dismay, this covers all machines I have access to)? If so, is there a minimum depth of function calls that I can rely on to be executed properly? I would hate to rewrite all my programs to do everything within main() without function calls, for the ultimate portability :-) Best regards, Sidney |
Re: why does this work ?
In article <bm8ne5$hf3$1@news.tudelft.nl>,
Sidney Cadot <sidney@jigsaw.nl> wrote: > #include <stdio.h> > > /* returns n! modulo 2^(number of bits in an unsigned long) */ > unsigned long f(unsigned long n) > { > return (n==0) ? 1 : f(n-1)*n; > } > > int main(void) > { > unsigned long z; > for(z=1;z!=0;z*=2) > { > printf("%lu %lu\n", z, f(z)); > fflush(stdout); > } > return 0; > } > > ---- > > As far as I can see, this is a perfectly valid C program that should > reach the 'return 0' statement always, were it not for the fact that in > all compilers I tried (one, actually) it terminates with a segmentation > fault of some sort, due to limited stack size. > > Is this 'incorrect behavior' of all these compilers, or is there some > wording in the Standard that covers for machines with a finite stack > (much to my dismay, this covers all machines I have access to)? > > If so, is there a minimum depth of function calls that I can rely on to > be executed properly? I would hate to rewrite all my programs to do > everything within main() without function calls, for the ultimate > portability :-) I suggest you start saving your money for a POWER4 with 64 GB of memory or so, which IBM will happily sell you for some six digit dollar number. Make sure that unsigned long is not more than 32 bit, though. |
Re: why does this work ?
>Joona I Palaste wrote:
>>There is no requirement for implementations to *have* a stack >>in the first place. In article <bm8ne5$hf3$1@news.tudelft.nl> Sidney Cadot <sidney@jigsaw.nl> writes: >This is the second time I see this posted over the last couple of days, >and you're surely right. In a technical sense, at least, and it *does* matter sometimes. The constraints in the standard force "stack-like behavior" for local variables inside functions (including any parameters), and I think it is not out of line to call this "a stack". But one should remember that this "stack" may well be implemented as, e.g., a linked list of frames: struct stackframe { struct stackframe *inner; unsigned char mem[]; /* C99 "flexible array member" syntax */ }; and the memory for each stack frame allocated out of a general storage pool, so that there is no fixed addressing relationship between any pair of stack frames. This is in fact the method used on early IBM 370 C compilers. (I imagine it is still used on S/370 architectures, since there is no dedicated "frame pointer" register, though as I recall R14 is somewhat conventional.) Other hardware that runs C code may have two or more hardware stacks, and/or multiple software stacks. Consider Moore's "Forth on a chip" systems, which have a call/return stack separate from their "value" stack on which one would pass parameters. Or look at the Pyramid, which had separate "control" and "data" stacks, although the control stack held register values which were often (probably "usually") data. >... is there a minimum depth of function calls that I can rely on to >be executed properly? I would hate to rewrite all my programs to do >everything within main() without function calls, for the ultimate >portability :-) I have never found one. The "Translation limits" section (at or near 5.2.4.1) is the logical place for something like "at least N function activations down from the initial call to main()", but there is no such wording. On the other hand, that section is not a good weapon against Evil Compilers, as it requires only that an implementation "translate and execute ... one program" that tests those limits. -- 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://67.40.109.61/torek/index.html (for the moment) Reading email is like searching for food in the garbage, thanks to spammers. |
Re: why does this work ?
On Sat, 11 Oct 2003 12:53:07 +0200, Sidney Cadot <sidney@jigsaw.nl>
wrote: >Joona I Palaste wrote: > >> <snip> >> There is no requirement for implementations to *have* a stack in the first place. > >This is the second time I see this posted over the last couple of days, >and you're surely right. But it does beg the following question: > >---- > >#include <stdio.h> > >/* returns n! modulo 2^(number of bits in an unsigned long) */ >unsigned long f(unsigned long n) >{ > return (n==0) ? 1 : f(n-1)*n; >} > >int main(void) >{ > unsigned long z; > for(z=1;z!=0;z*=2) > { > printf("%lu %lu\n", z, f(z)); > fflush(stdout); > } > return 0; >} > >---- > >As far as I can see, this is a perfectly valid C program that should >reach the 'return 0' statement always, were it not for the fact that in It is valid in the theoretical sense but it executes in the real world. >all compilers I tried (one, actually) it terminates with a segmentation >fault of some sort, due to limited stack size. > >Is this 'incorrect behavior' of all these compilers, or is there some >wording in the Standard that covers for machines with a finite stack >(much to my dismay, this covers all machines I have access to)? > >If so, is there a minimum depth of function calls that I can rely on to >be executed properly? I would hate to rewrite all my programs to do >everything within main() without function calls, for the ultimate >portability :-) All systems have limited resources. Even virtual memory is backed up in some kind of file. I could not find in the standard a minimum for the number of recursive function calls an implementation was required to support. It does state that a function can be recursively called at least once. Do you know how much data your system must save when a function is re-called? Usually, this includes information about the state of your task (such as the address to return to) and all automatic variables (those defined in your code and any generated by the compiler to hold intermediate results). There is probably more that I cannot think of at the moment. What would you accept as a reasonable estimate? 100 bytes just to make the arithmetic easier? ULONG_MAX is required to be greater than 4,000,000,000 (that's billion on my side of the pond but perhaps milliard on yours, 4*10^9 in any case). What will happen when z is 10,000,000 (a mere 10 million)? f will be recursively called 10 million times, requiring 1 gigabyte of storage. Is your task authorized to consume that much of your system resources? Does your system even have that much available? Even if you can support this, can you support z at 100 million requiring 10 gigabtyes? At 4 billion (milliard) requiring 400 gigabytes? What happens if long is 64 bits on your system? Would you be asking your question if your program simply issued malloc requests until no more memory was available? The only difference is that malloc fails "politely" by returning NULL. There doesn't seem to be any way for a recursion failure to be "polite." Both fail for exactly the same reason. Only the symptoms of that failure are different. Welcome to the limitations of practicality. <<Remove the del for email>> |
Re: why does this work ?
Hi Chris,
>>> [[does the Standard require a stack?]] > The constraints in the standard force "stack-like behavior" for > local variables inside functions (including any parameters), and > I think it is not out of line to call this "a stack". [...] As for me: If it walks like a stack and talks like a stack, so to say - I'd prefer to call it a stack. If I understand what you're saying correctly, the standard does not (of course!) force the underlying hardware to support anything stack-like, but the runtime model implies something that can in good faith only be called a stack (albeit perhaps one that implemented in software, as your IBM 370 and other examples show). Interesting. >>... is there a minimum depth of function calls that I can rely on to >>be executed properly? I would hate to rewrite all my programs to do >>everything within main() without function calls, for the ultimate >>portability :-) > > I have never found one. The "Translation limits" section (at or > near 5.2.4.1) is the logical place for something like "at least N > function activations down from the initial call to main()", but > there is no such wording. On the other hand, that section is not > a good weapon against Evil Compilers, as it requires only that an > implementation "translate and execute ... one program" that tests > those limits. That's interesting... Based on a literal reading of the standard at least, I'd say my sample program is fully compliant and there's no reason for it ever to not reach the 'return 0' statement. Now the actual behavior, segfaulting, is usually classified as a manifestation of 'undefined behavior' in other contexts. Moreover, it is obvious that one cannot sensibly expect arbitrarily deep function calls to work (although the standard doesn't give limits). To me, perhapse naively, this seems then like a point where the standard is not complete. Anybody care to comment on that point of view? Best regards, Sidney Cadot The Netherlands |
Re: why does this work ?
On Sat, 11 Oct 2003 12:53:07 +0200, in comp.lang.c , Sidney Cadot
<sidney@jigsaw.nl> wrote: snip prog that runs out of stack space >Is this 'incorrect behavior' of all these compilers, or is there some >wording in the Standard that covers for machines with a finite stack >(much to my dismay, this covers all machines I have access to)? The C standard sets limits on the size, number and so forth of objects that an implementation is required to provide. Infinite recursion, or even relatively deep recursion, tends to break them. See 5.2.4 of the Standard. -- Mark McIntyre CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html> CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html> ----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==---- http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups ---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =--- |
| All times are GMT. The time now is 03:57 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.