[comp.lang.c] MSC-all C's

richw@rosevax.Rosemount.COM (Rich Wagenknecht) (11/11/87)

I have two questions:

  1) What happens in C when a function returns a value which the
     calling line does not assign to a variable? Where does this
     value end up? (example: strcpy(str1,str2); ) Could someone
     explain the process that is gone through when a function is
     called?

  2) Specific to IBM Pc compilers. I am trying to write some
     disk routines (using DOS interrupts <-sp?) I am not sure which
     memory model I will need for a large application program I will
     soon write. How can I generalize these routines to work with any
     memory model. I am specifically concerned with pointers (near/far).

Thankyou in advance.
Rich Wagenknecht

firth@sei.cmu.edu (Robert Firth) (11/12/87)

In article <3094@rosevax.Rosemount.COM> richw@rosevax.Rosemount.COM (Rich Wagenknecht) writes:

>  1) What happens in C when a function returns a value which the
>     calling line does not assign to a variable? Where does this
>     value end up? (example: strcpy(str1,str2); ) Could someone
>     explain the process that is gone through when a function is
>     called?

Can't answer the other question, but this one maybe I can help.

If the function returns a "small" value, such as an int, then its
last action before returning is normally to compute the result and
leave it in a specific register (eg R0).  The caller then expects
to find it there.  So, for instance

	x = f()

will compile as

	call f
	store result from R0 (or wherever) into x

If you simply call the function thus

	f()

then the result still comes back in R0 but isn't used.  So it is
destroyed when the code next decides to use R0.

The case of a "large" value is different.  The proper way to implement
this is for the caller to create a temporary and pass a pointer to it.
So, given bigf() returning a large value (of a type T, say)

	x = bigf()

compiles into

	{ T temp
	  bigf (&temp)
	  x = temp
	}

which can sometimes be optimised to just bigf(&x).  The function of course
copies the return value into the thing pointed at by its (hidden) first
parameter.

If you now just call bigf(), then the compiler still must generate a
temporary and actually emit bigf(&temp), otherwise the poor function
will write its result through an undefined pointer.  C implementors
being what they are, I won't assert that all compilers get this right.

Finally, an older way of implementing things like bigf() had the function
store its result in a static temporary.  This is plain wrong, so I won't
discuss it further.

carroll@snail.UUCP (11/13/87)

	In most compilers, a certain register on the processor is used to
hold return values. When it is assigned, it is moved out of the register
and into the appropriate variable, or tested (as in if(open(...) < 0)). If
it is not used, then the value in the register is just overwritten next time
it's used. On '86 CPU's, it's usually ax, on most PDP style machines it's r0.

ftw@datacube.UUCP (11/14/87)

richw@rosevax.UUCP writes:

> I have two questions:

>   1) What happens in C when a function returns a value which the
>      calling line does not assign to a variable? Where does this
>      value end up? (example: strcpy(str1,str2); ) Could someone
>      explain the process that is gone through when a function is
>      called?

Usually, a function return value gets stuck in a spare register.  The
compiler vendor will will have a standard mechanisim for passing back
return values for functions.  For instance, most 68K C compilers that
I have come across will stick function returns in register d0; Whitesmiths
uses d7, etc.  Aggregates are more complicated.  If the caller does not
use the return value, it will remain where it was put until overwritten
by something else.

In a stack based machine, when a function is called, all the args to that
function are pushed on the stack in some agreed-upon order, along with
the return address.  The called function accesses its arguments by using
offsets from the current value of the stack pointer.  The stack is unwound
when the called function returns.


>  2) Specific to IBM Pc compilers. I am trying to write some
>     disk routines (using DOS interrupts <-sp?) I am not sure which
>     memory model I will need for a large application program I will
>     soon write. How can I generalize these routines to work with any
>     memory model. I am specifically concerned with pointers (near/far).

Someone else will have to take this one.  I do get the impression that
such a thing would be at least rather tricky.


> Thankyou in advance.
> Rich Wagenknecht



				Farrell T. Woods 

Datacube Inc. Systems / Software Group	4 Dearborn Rd. Peabody, Ma 01960
VOICE:	617-535-6644;	FAX: (617) 535-5643;  TWX: (710) 347-0125
INTERNET: ftw@datacube.COM
UUCP: {rutgers, ihnp4, mirror}!datacube!ftw

gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/14/87)

In article <3094@rosevax.Rosemount.COM> richw@rosevax.Rosemount.COM (Rich Wagenknecht) writes:
>  1) What happens in C when a function returns a value which the
>     calling line does not assign to a variable? Where does this
>     value end up? (example: strcpy(str1,str2); ) Could someone
>     explain the process that is gone through when a function is
>     called?

Just as with the value of "x = 1", the value of the expression
is used only if the programmer chooses to use it.  It is misleading
to ask where the value ends up; it is up to the compiler to do the
right thing (which amounts to not having the value "end up" anywhere
that it was not explicitly placed by the programmer).

The process that occurs when a function-call expression is evaluated
at run time is:
	1. The arguments are evaluated (in unspecified order).
	2. The formal parameter variables in the function definition
	receive the corresponding values of the arguments.
	3. The body of the function definition is evaluated until an
	explicit "return" expression is evaluated or the end of the
	body is reached (which constitutes an implicit "return;").
	4. If the function returns a value and its evaluation ended
	with a "return" that had a value as its operand, that value
	replaces the function invocation in the calling context, and
	that higher-level evaluation process resumes using that value.
	(If the value is not explicitly used by the programmer, then
	evaluation simply proceeds to the next expression.)
This is really no different from most programming languages that
support functions, although C is unusual in that all arguments are
passed by value (array names are apparent exceptions; by the funny C
rules for array names in various contexts, they are converted to
pointers to the first members of the arrays when passed as arguments,
which is similar to "call by reference" found in some languages).