[comp.lang.c] Args: var number & var types

jv0l+@andrew.cmu.edu (Justin Chris Vallon) (05/12/88)

Is there any way to declare a function to have two arguments point to the same
place in the stack-frame?  Let's say that I want to write the implementation of
foo which takes an optional argument based upon the first parameter:

{
  char c;
  int i;
  short s;
  long l;

  foo(0);     /* no optional argument */
  foo(1, c);  /* pass a character argument */
  foo(2, i);  /* pass an integer argument */
  foo(3, s);  /* pass a short arg */
  foo(4, l);  /* pass a long arg */
  foo(5, "Hello world"); /* pass a char* arg */
}

Could this be done?

-Justin
justin.vallon@andrew.cmu.edu

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/12/88)

In article <cWW=o4y00XcRh2E04h@andrew.cmu.edu> jv0l+@andrew.cmu.edu (Justin Chris Vallon) writes:
>Could this be done?

Do it right -- use unions.

jnh@ece-csc.UUCP (Joseph Nathan Hall) (05/12/88)

In article <cWW=o4y00XcRh2E04h@andrew.cmu.edu> jv0l+@andrew.cmu.edu (Justin Chris Vallon) writes:
>Is there any way to declare a function to have two arguments point to the same
>place in the stack-frame?  Let's say that I want to write the implementation of
>foo which takes an optional argument based upon the first parameter:
...

You can do this by a) using a variable-length argument list or b) passing your
argument(s) in a union.  Approach b) wastes a little space but is more
conventional, hence more easily understood and probably easier to port between
older compilers.

-- 
v   v sssss|| joseph hall                      || 201-1D Hampton Lee Court
 v v s   s || jnh@ece-csc.ncsu.edu (Internet)  || Cary, NC  27511
  v   sss  || the opinions expressed herein are not necessarily those of my
-----------|| employer, north carolina state university . . . . . . . . . . . 

carroll@snail.CS.UIUC.EDU (05/13/88)

/* Written  3:43 pm  May 11, 1988 by jv0l+@andrew.cmu.edu in snail:comp.lang.c */
/* ---------- "Args: var number & var types" ---------- */
Is there any way to declare a function to have two arguments point to the same
place in the stack-frame?  Let's say that I want to write the implementation of
foo which takes an optional argument based upon the first parameter:

{
  char c;
  int i;
  short s;
  long l;

  foo(0);     /* no optional argument */
  foo(1, c);  /* pass a character argument */
  foo(2, i);  /* pass an integer argument */
  foo(3, s);  /* pass a short arg */
  foo(4, l);  /* pass a long arg */
  foo(5, "Hello world"); /* pass a char* arg */
}
-Justin
justin.vallon@andrew.cmu.edu
/* End of text from snail:comp.lang.c */

union thing
    {
    char c;
    int i;
    short int s;
    long int l;
    char *q; /* in keeping with the 1 leter convention */
    } ;

void foo(type,object)
int type; union thing *object;
/* pointer, although many compilers allow pass-by-value union/structs */
    {
    switch(type)
	{
	case 0 : putchar(object->c); break;
	case 1 : printf("%d",object->i); break;
	...
	}
    }

main()
    {
    union thing fudge;
    foo(0,fudge.c='x',&fudge);
    foo(1,fudge.i=17,&fudge);
    ...
    /* this could be done with macro's, or better, just put the
       value into fudge instead of whatever other var, and then
       just call foo with foo(2,&fudge).
    */
    }

Alan M. Carroll		amc@woodshop.cs.uiuc.edu	carroll@s.cs.uiuc.edu
Grad Student (TA) / U of Ill - Urbana ...{ihnp4,convex}!uiucdcs!woodshop!amc
	"Too many fools who don't think twice
	 Too many ways to pay the price"  - AP & EW

chris@mimsy.UUCP (Chris Torek) (05/13/88)

In article <cWW=o4y00XcRh2E04h@andrew.cmu.edu> jv0l+@andrew.cmu.edu
(Justin Chris Vallon) writes:
[How would one implement a function foo such that ...]
>  foo(0);     /* no optional argument */
>  foo(1, c);  /* pass a character argument */
>  foo(2, i);  /* pass an integer argument */
>  foo(3, s);  /* pass a short arg */
>  foo(4, l);  /* pass a long arg */
>  foo(5, "Hello world"); /* pass a char* arg */

Doug Gwyn suggests using a union.  This is likely to work (by
which I mean more likely not to turn up implementation bugs and
perhaps less likely to confuse programmers), but is inconvenient
since C lacks aggregate constructors.  Here is a sample foo().

/* K&R C */			/* NeoC */
#include <varargs.h>		#include <stdarg.h>

void				void
foo(va_alist)			foo(int ind, ...)
	va_dcl
{				{
	va_list ap;			va_list ap;
	int ind;
	char c;				char c;
	int i;				int i;
	short s;			short s;
	long l;				long l;
	char *cp;			char *cp;

	va_start(ap);			va_start(ap, ind);
	ind = va_arg(ap, int);
					/* now copy version on left verbatim */
	switch (ind) {

	case NO_ARG:
		work0();
		break;

	/*
	 * nb: because char, short, and int are all extended to int, it
	 * is probably unnecessary to distinguish between them.
	 */
	case CHAR_ARG:
		c = va_arg(ap, int);
		work1(c);
		break;

	case INT_ARG:
		i = va_arg(ap, int);
		work2(i);
		break;

	case SHORT_ARG:
		s = va_arg(ap, int);
		work3(s);
		break;

	case LONG_ARG:
		l = va_arg(ap, long);
		work4(s);
		break;

	case STR_ARG:
		cp = va_arg(ap, char *);
		work5(cp);
		break;
	}

	va_end(ap);
}


/* note that neo-C makes an annoying semantic change to va_start */
/* (NEVER change the semantics without changing the name! grr..) */
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

karl@haddock.ISC.COM (Karl Heuer) (05/13/88)

In article <cWW=o4y00XcRh2E04h@andrew.cmu.edu> jv0l+@andrew.cmu.edu (Justin Chris Vallon) writes:
>Is there any way to declare a function to have two arguments point to the
>same place in the stack-frame?  Let's say that I want to write [a function]
>foo which takes an optional argument based upon the first parameter: ...
>  foo(0);     /* no optional argument */
>  foo(1, c);  /* pass a character argument */
>  foo(2, i);  /* pass an integer argument */
>  foo(3, s);  /* pass a short arg */
>  foo(4, l);  /* pass a long arg */
>  foo(5, "Hello world"); /* pass a char* arg */

Yes, it can be done, in at least two ways.  Doug Gwyn has suggested using
unions; this is awkward because (lacking a cast-to-union) you'd have to write
junk like "un.u_asint = i; foo(2, un);".  The other way is to use <stdarg.h>
(on ANSI implementations) or <varargs.h> (if you've got it).  In this case you
don't declare the second argument at all, but instead fetch its value from the
argument list via the va_arg macro.

N.B. When function foo() handles cases 1 and 3, the argument type must be
specified as "int", even if you want to store it in a smaller object:
    char c; ...
    c = va_arg(ap, int);

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

henry@utzoo.uucp (Henry Spencer) (05/14/88)

> Is there any way to declare a function to have two arguments point to the same
> place in the stack-frame? ...

Well, sort of.  If you can make the problem printf-like, with earlier
arguments of fixed types determining the variable-type arguments, then
whatever method your implementation uses for printf should suffice.
If your implementation has a <stdargs.h> header, use that.  Second choice is
<varargs.h>.  If you have neither of those, it's still possible but the code
will be highly implementation-specific and it's difficult to supply specific
advice.

Note that this is *not* a general way of having two arguments in the same
location; to do that you have to use unions, and doing *that* portably
requires that the caller know about it.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry