[comp.lang.c] return

) Seaman) (01/01/88)

I have been following the discussion of the return vs. exit
controversy, and have a couple of observations:

   1) If exit is perferred over return, the why does everyone agree
      that crt0 calls main, and then calls exit?  Whether it checks
      the return value from main is not my question.  The point is
      crt0 assumes that main will return control to it under normal
      circumstances.

   2) I work on an AT&T 3B15, an IBM PC (Turbo C and Microsoft C 5.0),
      and an Amiga 1000 (Manx 3.4a).  All these environments *expect*
      main to return to crt0.  Of course, if you want to return a
      non-zero value to your operating system, you should use exit.
      *But*, if a program exits normally, it should be returning zero,
      and none of the implementations I've seen discussed here would
      prevent that when using return (from main).

   3) On the AT&T 3B15, if I write code that *does not* use return
      from main as the logical end of the function (meaning, when
      all goes well), but uses exit instead, lint complains that I
      am returning a random value to the calling environment.


-- 
Chris Seaman            |    o\  /o
crs@cpsc6a.att.com <or> |      ||         See "Attack of the Killer Smiley"!
..!ihnp4!cpsc6a!crs     |   \vvvvvv/     Coming Soon to a newsgroup near you!
                        |    \____/ 

chip@ateng.UUCP (Chip Salzenberg) (01/04/88)

In article <441@cpsc6b.cpsc6a.att.com> crs@cpsc6b.cpsc6a.att.com (Chris (Batches? We don't need no steenking batches!) Seaman) writes:
>   1) If exit is perferred over return, the why does everyone agree
>      that crt0 calls main, and then calls exit?  Whether it checks
>      the return value from main is not my question.  The point is
>      crt0 assumes that main will return control to it under normal
>      circumstances.

Consider that a function parameter, left undeclared, defaults to type
"int".  Does this mean that the compiler "expects" you to leave integer
function parameters undeclared?  Of course not.

It is legal to return from main(), but it is neither required nor
encouraged.

>   3) On the AT&T 3B15, if I write code that *does not* use return
>      from main as the logical end of the function (meaning, when
>      all goes well), but uses exit instead, lint complains that I
>      am returning a random value to the calling environment.

You should read the lint manual.  Try this:

main()
{
	...
	/* Time to go home. */
	exit(0);
	/* NOTREACHED */        /* Tell lint that exit() doesn't return. */
}
-- 
Chip Salzenberg                 UUCP: "{codas,uunet}!ateng!chip"
A T Engineering                 My employer's opinions are a trade secret.
    "Anything that works is better than anything that doesn't."  -- me

marcoz@MARCOZ.BOLTZ.CS.CMU.EDU (Marco Zagha) (03/07/89)

Can anybody explain how returning a structure from a function is
typically implemented.  Assume it is too big to use registers.
Is it returned on the stack?  Where does the return structure
go in relation to parameters to the function?  For a stack that
grows downward, is the return value above the parameters,
below the parameters, or does the return statement overwrite
the parameters?

Since I suspect this is implementation dependent, please specify
what implementation you are describing.

== Marco (marcoz@cs.cmu.edu)

P.S. I am *not* writing any code that depends on the implementation.
I am just curious.
-- 

dave@motto.UUCP (dave brown) (03/07/89)

In article <4425@pt.cs.cmu.edu> marcoz@MARCOZ.BOLTZ.CS.CMU.EDU.UUCP writes:
>Can anybody explain how returning a structure from a function is
>typically implemented.

Here are two ways that I've seen.

The first is in the C compiler for Sys V/68 (Motorola's System V port for
the 68000).  Any routine that returned a struct has an invisible static
area the same size as the struct.  The return statement copies the
struct value into this area.  Code in the calling routine just
after the call, copies it to the variable which is to receive it.

The second is in the Intermetrics 68000 C compiler.  This is a cross-
compiler for the 68000, hosted under VAX Ultrix.  If a function
returns a struct, the compiler inserts a pointer on the stack in
front of the first argument.  This pointer is the address of the
receiving struct variable.  The function itself copies the return value
through the pointer into the receiving variable.

We found out about the second method when a programmer who wasn't using
the return value called the function without declaring its return type.
His first argument was then taken as the return value address, etc., etc.

 -----------------------------------------------------------------------------
|  David C. Brown		|  uunet!mnetor!motto!dave		      |
|  Motorola Canada, Ltd.	|  416-499-1441 ext 3708		      |
|  Communications Division	|  Disclaimer: Motorola is a very big company |
 -----------------------------------------------------------------------------

henry@utzoo.uucp (Henry Spencer) (03/08/89)

In article <4425@pt.cs.cmu.edu> marcoz@MARCOZ.BOLTZ.CS.CMU.EDU (Marco Zagha) writes:
>Can anybody explain how returning a structure from a function is
>typically implemented.  Assume it is too big to use registers.
>Is it returned on the stack?  Where does the return structure
>go in relation to parameters to the function?  For a stack that
>grows downward, is the return value above the parameters,
>below the parameters, or does the return statement overwrite
>the parameters?

The general answer, as you suspected, is "it depends".  An additional
constraint, tricky to satisfy, is that preferably no dire harm should
come about if the function has not been declared properly at the site
of the call (i.e. function returns struct but caller is expecting int).
C programmers have a nasty tendency to assume that if they're just
throwing away the return value, it doesn't matter what type it is.

Just about every permutation of putting it on the stack is probably
in use in some compiler or other.  Probably the best approach, although
it's one that requires correct declaration, is to have the caller pass
in a pointer (as an invisible extra parameter) to where he wants the
return value put.  Even stranger approaches have been used in some
implementations; the original pdp11 Ritchie compiler allocated a static
struct variable for each struct-returning function, and used that as a
temporary in the return sequence (yes, this meant that such functions
were not completely reentrant).
-- 
The Earth is our mother;       |     Henry Spencer at U of Toronto Zoology
our nine months are up.        | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

karl@haddock.ima.isc.com (Karl Heuer) (03/08/89)

In article <4425@pt.cs.cmu.edu> marcoz@MARCOZ.BOLTZ.CS.CMU.EDU (Marco Zagha) writes:
>Can anybody explain how returning a structure from a function is
>typically implemented.  Assume it is too big to use registers.

Some broken implementations use a static area in the callee and just return
its address.  This mechanism is not reentrant, is forbidden by the pANS, and
will be considered no further in this article.

Generally, the caller finds space for the object, and ensures that the callee
knows the location of this space.  (Small structs are a special case of this,
where the caller finds space in the registers, and the callee already knows
the location, since it's constant.  Note that `location' does not mean
`address' in this example.)  Usually the second part of this protocol is
handled by having the caller pass the address of the struct as a `hidden
argument'; this can be done either using the normal argument-passing scheme
(so that f(x) generates code that looks like f(&hidden, x)) or any other
consistent strategy (some compilers have the caller put the address in a known
register, which is not otherwise used in argument passing).

The first part of the protocol can be achieved, if necessary, by reserving
enough stack space ahead of time, and passing &hidden as if `hidden' were an
auto variable.  However, since the usual thing to do with a struct-returning
function is to store its return value in a struct, the expression `y=f(x)',
which would normally generate code resembling `f(&hidden, x); y=x', can often
be optimized to `f(&y, x)'.  I leave it as an exercise for the student to
determine the conditions under which this optimization is legal.

>[If it's on the stack,] where does the return structure go in relation to
>parameters to the function?

It's normal for the arguments to be the last things pushed on the stack, so
that they can be cleaned up easily.  Thus the space for the return value
itself ought to be upward of the args, if the stack grows downward.

>Since I suspect this is implementation dependent, please specify
>what implementation you are describing.

Most of what I've said is pretty generic; read `vax' for a concrete example.
I believe it was the 3b20 that used the special register.

Btw, the program
	typedef struct { char junk[8192]; } foo;
	static foo dummy;
	foo f() { return dummy; }
	main() { (void)f(); }
can be used to test for a certain compiler bug.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

feg@clyde.ATT.COM (Forrest Gehrke) (03/10/89)

In article <1989Mar7.163952.20063@utzoo.uucp>, henry@utzoo.uucp (Henry Spencer) writes:
.>  [.....deletes] 
> Just about every permutation of putting it on the stack is probably
> in use in some compiler or other.  Probably the best approach, although
> it's one that requires correct declaration, is to have the caller pass
> in a pointer (as an invisible extra parameter) to where he wants the
> return value put.  Even stranger approaches have been used in some
.>  [deletes]




I don't understand how a programmer calls a function and passes
an "invisible extra parameter".  What device does he use to
accomplish this? .....Or, are you talking about the compiler
programmer?

Forrest Gehrke

henry@utzoo.uucp (Henry Spencer) (03/14/89)

In article <42110@clyde.ATT.COM> feg@clyde.ATT.COM (Forrest Gehrke) writes:
>> Just about every permutation of putting it on the stack is probably
>> in use in some compiler or other.  Probably the best approach, although
>> it's one that requires correct declaration, is to have the caller pass
>> in a pointer (as an invisible extra parameter) to where he wants the
>> return value put...
>
>I don't understand how a programmer calls a function and passes
>an "invisible extra parameter".  What device does he use to
>accomplish this? .....Or, are you talking about the compiler
>programmer?

The programmer has no say in the matter, any more than he has a say in how
a returned struct is put on the stack in an implementation that uses the
stack.  This is entirely the compiler's job.
-- 
Welcome to Mars!  Your         |     Henry Spencer at U of Toronto Zoology
passport and visa, comrade?    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

mdfreed@ziebmef.uucp (Mark Freedman) (03/19/89)

In article <11977@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <4425@pt.cs.cmu.edu> marcoz@MARCOZ.BOLTZ.CS.CMU.EDU (Marco Zagha) writes:
>>Can anybody explain how returning a structure from a function is
>>typically implemented.  Assume it is too big to use registers.
>
>Some broken implementations use a static area in the callee and just return
>its address.  This mechanism is not reentrant, is forbidden by the pANS, and
>will be considered no further in this article.
>
   That implies that  1) the MS-DOS implementations with which I'm familiar
(Turbo-C 2.0, Datalight C 3.05, Lattice C 3.10), and probably several with
which I'm not, are broken   2) the marketeers for these companies have 
gotten a bit carried away when claiming dpANS compliance.
   Is anyone aware of MS-DOS compilers which implement structure returns 
according to dpANS ? Is anyone aware of software companies which intend to
correct the broken implementation ?

ark@alice.UUCP (Andrew Koenig) (03/22/89)

> In article <4425@pt.cs.cmu.edu> marcoz@MARCOZ.BOLTZ.CS.CMU.EDU (Marco Zagha) writes:

> Some broken implementations use a static area in the callee and just return
> its address.  This mechanism is not reentrant, is forbidden by the pANS, and
> will be considered no further in this article.

I can't find the place in my draft ANSI C spec that prohibits this.
Can you enlighten me?
-- 
				--Andrew Koenig
				  ark@europa.att.com

afscian@violet.waterloo.edu (Anthony Scian) (03/22/89)

In article <1989Mar18.144546.10605@ziebmef.uucp> mdfreed@ziebmef.UUCP (Mark Freedman) writes:
>>Some broken implementations use a static area in the callee and just return
>>its address.  This mechanism is not reentrant, is forbidden by the pANS, and
>>will be considered no further in this article.
>>
>   That implies that  1) the MS-DOS implementations with which I'm familiar
>(Turbo-C 2.0, Datalight C 3.05, Lattice C 3.10), and probably several with
>which I'm not, are broken   2) the marketeers for these companies have 
>gotten a bit carried away when claiming dpANS compliance.
>   Is anyone aware of MS-DOS compilers which implement structure returns 
>according to dpANS ? Is anyone aware of software companies which intend to
>correct the broken implementation ?

WATCOM C7.0 is one MS-DOS ANSI C compiler that did it right (with the
best optimizer, also). By the way, you forgot to include Microsoft's
C compiler in your list of broken compilers (even their OS/2 version!).

-- Anthony Scian           \\ "Working with roots and twigs, Tom managed
afscian@violet.uwaterloo.ca \\ to build a working tractor beam. Then he
afscian@violet.waterloo.edu  \\ waited ..." - Aarrr Trek: The Wrath of Tom