Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   why does this work ? (http://www.velocityreviews.com/forums/t315703-why-does-this-work.html)

Bamber 10-10-2003 11:03 AM

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.

Joona I Palaste 10-10-2003 11:06 AM

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

Tristan Miller 10-10-2003 12:07 PM

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

Dan Pop 10-10-2003 02:36 PM

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

Sidney Cadot 10-11-2003 10:53 AM

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



Christian Bau 10-11-2003 12:24 PM

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.

Chris Torek 10-11-2003 04:42 PM

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 (4039.22'N, 11150.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.

Barry Schwarz 10-11-2003 05:17 PM

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>>

Sidney Cadot 10-11-2003 10:12 PM

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


Mark McIntyre 10-11-2003 10:31 PM

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 04:24 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.