[comp.lang.c] Why pass structs?

ed360463@cisunx.UUCP (02/27/87)

I have been aware of the post V7 C compilers passing and
returning structs from procedures, and I am curious as to
why.

Passing structures as a whole seems to violate my impression
of the nature of C.  I feel that a good reason for passing
arrays by reference (yes, I know that the pointer is passed by
value :-) is to save an enormous ammount of stack and CPU time.

To pass a structure by value seems to require an arbitrarily
large amount of stack; but more importantly, non-atomic
stack operations.  That is, that I can push a long, int, char
or any pointer with (hopefully) one machine-op.  To pass 
a structure would require a number of pushes, a block-copy-op,
or some looping copy code.

I imagine that the people who added this to C had good reason,
so could someone please tell me what I am missing or have
gotten wrong?

Thank you
-- 
matt wartell
university of pittsburgh
{the known world}!pitt!cisunx!ed360463

ron@brl-sem.UUCP (02/27/87)

In article <3346@cisunx.UUCP>, ed360463@cisunx.UUCP (wartell    m) writes:
> 
> To pass a structure by value seems to require an arbitrarily
> large amount of stack; but more importantly, non-atomic
> stack operations.  That is, that I can push a long, int, char
> or any pointer with (hopefully) one machine-op.  To pass 
> a structure would require a number of pushes, a block-copy-op,
> or some looping copy code.

Well your hopes are wrong.  There are many machines that can not
push anything on the stack in one operation.  Even more enlighted
machines with autodecrement indexed stack pointers or push instructions
can't push the larger datatypes on the stack with one instruction.

I'm not sure what point you are trying to make.  There is a lot of
stuff in the subroutine call sequence that is a lot more vulnerable
to interruption than a single argument push. 

> I imagine that the people who added this to C had good reason,
> so could someone please tell me what I am missing or have
> gotten wrong?

Mostly because it seemed that it would be silly not to.  You can
push and return any other data type (well almost any other, unions
still don't work mostly).  The only reason STRUCTS were initially
left out was because they weren't easy to do.

-Ron

guy@gorodish.UUCP (02/27/87)

>Passing structures as a whole seems to violate my impression
>of the nature of C.  I feel that a good reason for passing
>arrays by reference (yes, I know that the pointer is passed by
>value :-) is to save an enormous ammount of stack and CPU time.

Yes, but the mere fact that something takes a lot of CPU time or
stack space isn't sufficient to indicate that C shouldn't do it; some
people, for instance, might argue that C implementations on the VAX
shouldn't use "calls", because they take a lot of time :-).

>To pass a structure by value seems to require an arbitrarily
>large amount of stack; but more importantly, non-atomic
>stack operations.  That is, that I can push a long, int, char
>or any pointer with (hopefully) one machine-op.

Well, you can't.  For instance, on the machine on which C was
originally implemented, you *can't* push a long with one machine
instruction.  Again, "can I do this in a machine instruction" is the
wrong question, as is "is this operation atomic".  (Remember, the
instruction to push such an item may not be atomic, even if it is
done in one machine instruction; what if it takes a page fault when
doing the push, or gets a segmentation violation because the stack
hasn't grown far enough yet?)

>I imagine that the people who added this to C had good reason,
>so could someone please tell me what I am missing or have
>gotten wrong?

According to Dennis Ritchie (at least as far as I remember his answer to
this question), the reason why structure assignment, structure-valued
arguments, and structure-valued functions were added was to make C
treat all scalar objects in a similar fashion.

herndon@umn-cs.UUCP (03/02/87)

  Maybe my argument will be silly too, but the arguments that
I have seen so far strike me as hilarious.
  As far as I can figure, no operation in original C ever did
anything that incurred non-obvious costs in either space or time.
By significant, I mean such as scanning an object of large size,
allocating space for a pass-by-value array, etc.  The user, if
he needed to copy a structure or allocate a large array, was
forced to do this himself, *explicitly*.  Where C did allocate
space for large objects, the declaration was apparent, e.g.,
"struct foo bletch[10000];".
  This is convenient for those who write performance sensitive
code -- no innocent looking statement is going to chew up megabytes
and megacycles of resources.
  In today's enlightened world, however, programmer convenience
is more heavily stressed, and if the user wants it, the user gets
it.  My personal opinion is that this is the correct choice.
I have, however, on many occasions, in a production environment,
seen otherwise competent programmers wondering in disbelief at
their programs when they get run-time errors from procedures
that pass LARGE parameters by value on machines with memories
only somewhat bigger than the parameters.
  It still amazes me how little some "professional programmers"
understand "high-level language" compilers.

decot@hpisod2.UUCP (03/02/87)

> Mostly because it seemed that it would be silly not to.  You can
> push and return any other data type (well almost any other, unions
> still don't work mostly).  The only reason STRUCTS were initially
> left out was because they weren't easy to do.

Arrays were also left out.  The only type of thing you still can't
assign, pass, or return.  Silly.

And arrays are just as easy as structs to manipulate.  It's just that
it's difficult to find an inutitive syntax for array lvalues since the
only reasonable one was foolishly grabbed to mean "no, you see, when it's
an array name, it's really a pointer to the first element of the array,
not the array itself, so that it looks sort of like you can pass arrays
by value".

Therefore, here's what I consider to be the next best syntax available for
specifying array lvalues:

   	identifier []

This refers to the entire array whose name is identifier.  It is an invalid
construction where the size of the array is not known.

   #define ARRSIZ 20

   main ()
   {
      int (reverse())[ARRSIZ];	/* function returning array [ARRSIZ] of int */

      int arr[ARRSIZ] = "this is amazing";

	arr[] = reverse(arr[]);
	printf("%s\n", arr);
   }

   int (reverse(s))[ARRSIZ]
   char s[ARRSIZ];
   {
     char tmp[ARRSIZ], *tp = tmp;
     int i;

       for (i = strlen(s)-1; i >= 0; i--)
	   *tp++ = s[i];

       *tp = '\0';

       return tmp[];
    }

Dave Decot
hpda!decot

decot@hpisod2.HP.COM (Dave Decot) (03/04/87)

The example I provided to demonstrate a syntax for array lvalues incorrectly
included several declarations for items which should have been "char" instead
of "int".  Here's the example again, corrected.

Dave Decot
hpda!decot


#define ARRSIZ 20

main ()
{
  char (reverse())[ARRSIZ];	/* function returning array [ARRSIZ] of char */

  char arr[ARRSIZ] = "this is amazing";

    arr[] = reverse(arr[]);
    printf("%s\n", arr);
}

char (reverse(s))[ARRSIZ]
char s[ARRSIZ];
{
 char tmp[ARRSIZ], *tp = tmp;
 int i;

   for (i = strlen(s)-1; i >= 0; i--)
       *tp++ = s[i];

   *tp = '\0';

   return tmp[];
}

cramer@kontron.UUCP (03/04/87)

> I have been aware of the post V7 C compilers passing and
> returning structs from procedures, and I am curious as to
> why.
> 
> Passing structures as a whole seems to violate my impression
> of the nature of C.  I feel that a good reason for passing
> arrays by reference (yes, I know that the pointer is passed by
> value :-) is to save an enormous ammount of stack and CPU time.
> 
> To pass a structure by value seems to require an arbitrarily
> large amount of stack; but more importantly, non-atomic
> stack operations.  That is, that I can push a long, int, char
> or any pointer with (hopefully) one machine-op.  To pass 
> a structure would require a number of pushes, a block-copy-op,
> or some looping copy code.
> 
> I imagine that the people who added this to C had good reason,
> so could someone please tell me what I am missing or have
> gotten wrong?
> 
> matt wartell

One reason I have for occasionally passing a structure, rather than a
pointer to the structure, is if the structure is purely an input, and
I want to make sure that the called function doesn't alter the caller's
copy of the structure.

Clayton E. Cramer

markb@sdcrdcf.UUCP (03/04/87)

I always thought that it was added so that people who do complex math
would not have do any pointer hacking.  It is a lot nicer to be able to
write:

a = c_add(c_mul(b,c),d);

then

{  struct cmplx t;
   c_mul(&t,&b,&c);
   c_add(&a,&t,&d);
}

Mark Biggar
{allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb

aglew@ccvaxa.UUCP (03/12/87)

...> Why pass structs by value?

I occasionally feel uncomfortable passing structs by value,
and receiving them as the return value of the function.

Frequently because the struct starts offsmall, 16 - 32 bits
(eg. struct RectCoord { short x, y; }), so I say "I should use
pass by value here because they structure is no bigger than an
int". But then I start adding stuff to the struct, more fields,
reference counts...

The only things that I don't feel guilty about are
    typedef struct Complex {
    	float re, im;
    } Complex;
and
    typedef LongLong {
    	unsigned hi, low;
    } LongLong;
the latter because the machine I work on has 64 bit integer instructions,
though the C compiler doesn't give you access to them.

rjv@ihdev.UUCP (03/12/87)

In article <28700009@ccvaxa> aglew@ccvaxa.UUCP writes:
>
>...> Why pass structs by value?

because my struct is a chess-board, and i happen to be doing some
recursive backtracking algorithms  (for example)

	ron vaughn	...!ihnp4!ihdev!rjv