[comp.lang.c] Value, value, who's got the value?

scs@vax3.iti.org (Steve Simmons) (04/27/89)

Consider the following program:

int	func1()
{
	int b ;

	b = 2 ;
}

int	func2()
{
	int c = 3 ;

	c ;
}

main()
{
	int a = 1 ;
	printf( "Value of a is %d\n", a ) ;
	a = func1() ;
	printf( "Value of a is %d\n", a ) ;
	a = func2() ;
	printf( "Value of a is %d\n", a ) ;
}

Compile and run this on a UNIX-PC (system V) under standard cc or
with gcc, and the result is:
	Value of a is 1
	Value of a is 2
	Value of a is 3

On BSD43. with standard cc or gcc, the result is
	Value of a is 1
	Value of a is 0
	Value of a is 0

Several questions: why does the OS make a difference; why does
System V get it 'right' (even tho the code is wrong); why do
none of these flag func2 as having a syntax error?

   Steve Simmons         Just another midwestern boy
   scs@vax3.iti.org  -- or -- ...!sharkey!itivax!scs
         "Hey...you *can* get here from here!"

gwyn@smoke.BRL.MIL (Doug Gwyn) (04/27/89)

In article <1044@itivax.iti.org> scs@vax3.iti.org (Steve Simmons) writes:
>int	func2()
>{
>	int c = 3 ;
>	c ;
>}

>Several questions: why does the OS make a difference; why does
>System V get it 'right' (even tho the code is wrong); why do
>none of these flag func2 as having a syntax error?

The function value was whatever was accidentally in the return
register.

This is yet another case of fortuitous accidents and lack of
diagnostic ability in the compiler.  In this case, the error
is in not returning a value for the function; because of long
historical practice before "void" was introduced, int-valued
functions in old code are often used like we would currently
use void-valued functions.  Therefore the compiler deliberately
is silent about such an error.

However, there is no syntax error; "c;" is a valid albeit
useless statement.

Why are you posting these bugs, anyway?

henry@utzoo.uucp (Henry Spencer) (04/27/89)

In article <1044@itivax.iti.org> scs@vax3.iti.org (Steve Simmons) writes:
>int	func1()
>{
>	int b ;
>	b = 2 ;
>}
>int	func2()
>{
>	int c = 3 ;
>	c ;
>}
> ...
>Several questions: why does the OS make a difference; why does
>System V get it 'right' (even tho the code is wrong); why do
>none of these flag func2 as having a syntax error?

It's the compiler, not the OS, that makes the difference.  Neither of
those functions returns a value at all.  Some compilers will fortuitously
build the value of the last expression you evaluate in the same register
that is used to return a value, so it will appear that the "right" value
was returned.  There is no syntax error in func2, although the last
statement in func2 evaluates an expression with no side effects and then
throws the value away, which is kind of pointless (but legal).
-- 
Mars in 1980s:  USSR, 2 tries, |     Henry Spencer at U of Toronto Zoology
2 failures; USA, 0 tries.      | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

tim@crackle.amd.com (Tim Olson) (04/27/89)

In article <1044@itivax.iti.org> scs@vax3.iti.org (Steve Simmons) writes:
| 
| Consider the following program:
| 
| int	func1()
| {
| 	int b ;
| 
| 	b = 2 ;
| }
| 
| int	func2()
| {
| 	int c = 3 ;
| 
| 	c ;
| }
| 
| main()
| {
| 	int a = 1 ;
| 	printf( "Value of a is %d\n", a ) ;
| 	a = func1() ;
| 	printf( "Value of a is %d\n", a ) ;
| 	a = func2() ;
| 	printf( "Value of a is %d\n", a ) ;
| }
| 
| Compile and run this on a UNIX-PC (system V) under standard cc or
| with gcc, and the result is:
| 	Value of a is 1
| 	Value of a is 2
| 	Value of a is 3
| 
| On BSD43. with standard cc or gcc, the result is
| 	Value of a is 1
| 	Value of a is 0
| 	Value of a is 0
| 
| Several questions: why does the OS make a difference;

The OS doesn't cause the difference -- the compiler does.  Since func1
and func2 have no return statements, the value returned is whatever last
happend to be placed in the return-value location. On your UNIX-PC, this
is probably the same register as the first "temp" register that gets
assigned during expression evaluation.  On the BSD machine, it isn't.

| why does
| System V get it 'right' (even tho the code is wrong);

The compilers on that machine under that OS just happened to do what you
thought should happen.  The code is wrong, because there are no explicit
return statements.

| why do
| none of these flag func2 as having a syntax error?

Because it isn't a syntax error -- it is a legal (although useless)
expression.  Remember that in C, assignments aren't statements -- they
are expressions.

Here is what our local C compiler had to say about your program:

w "t.c",L1/C9:  func1: Function has no return statement.
w "t.c",L12/C9: c: Expression has no side-effects.
w "t.c",L8/C9:  func2: Function has no return statement.
w "t.c",L18/C9: printf: Function called but not defined.


	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

bills@sequent.UUCP (Bill Sears) (04/28/89)

In article <1044@itivax.iti.org> scs@vax3.iti.org (Steve Simmons) writes:
>
>Several questions: why does the OS make a difference; why does
>System V get it 'right' (even tho the code is wrong);
>
Actually, there is no "right" output for this program.  According to
K&R (version 1, sorry) pp23-24:  "a 'return' statement with no expression
causes control, but no useful value, to be returned to the caller, as
does "falling off the end" of a function by reaching the terminating
right brace."
Some compilers pass return expressions back through registers.  If no
explicit value is returned, the value which is used is whatever value
is in the register when it is evaluated.  Evidently, the SYSV compiler
is using the return register to do the computation that you specify in
the function.  Since no explicit value is returned, the value that is
left in the register when control returns to the caller is the value
of the expression in the function.
>
>why do none of these flag func2 as having a syntax error?
>
Because func2 doesn't have a syntax error.  C treats an expression
the same way it treats a statement so that functions that return
a value which is sometimes ignored don't fail.  For example:  The
close(2) system call returns a value (and hence is an expression)
to indicate the success or failure of the operation.  But most
programs do not check the return value (what are you supposed
to do?  The usual way close will fail is if the supplied file
descriptor is not open.  In which case the outcome is the same,
the fd is closed :-).

scs@vax3.iti.org (Steve Simmons) (04/28/89)

In article <10149@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>Why are you posting these bugs, anyway?

Dreystadt and I had both just come out of a BLISS-10 programming
environment, and some of the C features we saw really smacked of
an expression language.  We experimented to see just how far it
went, and on the compiler we had at the time it was amazingly far.
The
	var = if ( test ) foo ; else bar ;
did work on that compiler, and it seemed to stick almost every
result into the value register whether needed or not.  In fact, the
only 'expression' whose value we couldn't pick up was a switch
statement.

Over time these 'features' seemed to go away.  I suspect this was
largely because of the development of 'void' as a type and permitting
structures as passed and returned values.  I wanted to see if (a)
anybody else had once used these 'features', and (b) if people thought
they were useful.  Just sneakily tossing out an idea...

   Steve Simmons         Just another midwestern boy
   scs@vax3.iti.org  -- or -- ...!sharkey!itivax!scs
         "Hey...you *can* get here from here!"

dg@lakart.UUCP (David Goodenough) (04/28/89)

From article <1044@itivax.iti.org>, by scs@vax3.iti.org (Steve Simmons):
] Consider the following program:
] 
] int	func1()
] {
] 	int b ;
] 	b = 2 ;
] }
] 
] int	func2()
] {
] 	int c = 3 ;
] 	c ;
] }
] 
] main()
] {
] 	int a = 1 ;
] 	printf( "Value of a is %d\n", a ) ;
] 	a = func1() ;
] 	printf( "Value of a is %d\n", a ) ;
] 	a = func2() ;
] 	printf( "Value of a is %d\n", a ) ;
] }
] 
] Compile and run this on a UNIX-PC (system V) under standard cc or
] with gcc, and the result is:
] 	Value of a is 1
] 	Value of a is 2
] 	Value of a is 3
] 
] On BSD43. with standard cc or gcc, the result is
] 	Value of a is 1
] 	Value of a is 0
] 	Value of a is 0
] 
] Several questions: why does the OS make a difference;

It's not the OS, it's the compiler. Since you didn't say what func1() and
func2() return explicitly, they return whatever happens to be in registers
at the time. On a 68020, generally the return value comes back in d0, on
a 286 / 386 machine I'd guess it'd be in ax, although what you'd do with
a long I'm not sure.

] why does
] System V get it 'right' (even tho the code is wrong);

Both get it right, since the return value of a function without a

	return expr ;

is undefined.

] why do
] none of these flag func2 as having a syntax error?

Because it doesn't have one.

statement ::=   ...... | expr ; | .........

expr ::= ....... | variable | .........

Hence

	int i;

	i;

is syntactically correct.
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

jeremyr@cs.qmc.ac.uk (Jeremy Roussak) (04/29/89)

In article <1044@itivax.iti.org> scs@vax3.iti.org (Steve Simmons) writes:
>
>Consider the following program:
>
>int	func1()
>{
>	int b ;
>
>	b = 2 ;
>}
>
>int	func2()
>{
>	int c = 3 ;
>
>	c ;
>}
>
>main()
>{
>	int a = 1 ;
>	printf( "Value of a is %d\n", a ) ;
>	a = func1() ;
>	printf( "Value of a is %d\n", a ) ;
>	a = func2() ;
>	printf( "Value of a is %d\n", a ) ;
>}
>
>Compile and run this on a UNIX-PC (system V) under standard cc or
>with gcc, and the result is:
>	Value of a is 1
>	Value of a is 2
>	Value of a is 3
>
>On BSD43. with standard cc or gcc, the result is
>	Value of a is 1
>	Value of a is 0
>	Value of a is 0
>
>Several questions: why does the OS make a difference; why does
>System V get it 'right' (even tho the code is wrong); why do
>none of these flag func2 as having a syntax error?

To answer your questions in reverse order, no syntax error is flagged
because there is no syntax error.  A statement in C is simply an expression.
The statement a+3; is perfectly legal: the compiler will add 3 to a and
blissfully throw the result away.  Think of the "statement" i++;

It's not so much the  OS that makes the difference as the way the compiler
generates code.  If it leaves values used in assignments lying around
in a place where they might be interpreted later as results from a function,
and your function carelessly doesn't define a return value, you'll
get a spurious return value.  In your case, this is the value you want
but haven't written the code to get.  To choose a silly example, some
68000 C compilers use d0 to return function results.  If an assignment
   a=3
generated code like
   move #3,d0
   move d0,a   (not that it would, one hopes!)
then the value 3 would be lying around in d0 at return time.

Simple, eh?

Jeremy Roussak       Just a part-time hacker

geoff@cs.warwick.ac.uk (Geoff Rimmer) (04/29/89)

In article <1044@itivax.iti.org> scs@vax3.iti.org (Steve Simmons) writes:

> int	func1() { int b ; b = 2 ; } 
> int	func2() { int c=3 ; c; }
> 
> main() 
> {
> 	   int a = 1 ;
> 	   printf( "Value of a is %d\n", a ) ;
> 	   a = func1() ;
> 	   printf( "Value of a is %d\n", a ) ;
> 	   a = func2() ;
> 	   printf( "Value of a is %d\n", a ) ;
> }
> 

Get a compiler that loves to complain!  gcc will do just fine.  It'll
print a warning saying that func1 and func2 are *supposed* to return
ints, but that nothing is in fact returned.  The idea of this warning
is to stop you thinking that func1() should always return 2 on every
compiler.  It may happen, it may not.  On our system, the return value
will simply be whatever is left in the d0 register.  For example, the
following program:

int func() { int b; b = 2; }
int main() { int a; a = func(); }

produces the following assembler code for func():

_func:
	link a6,#-4         ; get 4 bytes for b.
	moveq #2,d0         ; set register d0 to 2.
	movel d0,a6@(-4)    ; move 2 into b.
L1:
	unlk a6		    ; cleanup heap.
	rts		    ; return to main()

and this for main()

_main:
	link a6,#-4         ; get 4 bytes for a.
	jbsr _func	    ; jump to func()
	movel d0,a6@(-4)    ; move d0 into a.  So a becomes 2.
L2:
	unlk a6	
	rts

The compiler writers *could* have implemented this in a totally
different way.  They could easily have chosen a different register to
return values from functions, and then, you would get unpredictable
values.

"Glad to be of service!"
Geoff

	/---------------------------------------------------------------\
	|	GEOFF RIMMER  - Friend of fax booths, ANSI C, PCBH,	|
	|			phone *numbers*	& MPFC & printf		|
	|	email	: geoff@uk.ac.warwick.emerald			|
	|	address : Computer Science Dept, Warwick University, 	|
	|		  Coventry, England.				|
	|	PHONE	: +44 203 692320 (10 lines) If I'm out please	|
	|			   leave a message with my secretary.	|
	|	FAX	: +44 865 726753				|
	\---------------------------------------------------------------/