🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.c.moderated
Article #2076

Variable param for non-vararg subr. calls

#2076
From: John Shalf
Date: Mon, 26 Feb 1996 12:50
122 lines
5413 bytes
<Note to moderator>:  
	I don't know if this is appropriate for this 
conference but I've found comp.lang.c filled with newbie C crap and 
comp.std.c filled with religious wars over default type promotion in 
the ANSI standard.  Hopefully this conf. is the place to ask arcane 
questions. 
</Note to moderator>

	[Although C, of course, just uses stdarg, this is an interesting
	 question, and I can't think of a better place. -mod]

Varargs allows you to unpack a variable number of arguments from a 
subroutine call at runtime.  You would think there would be a way to 
*pack* a variable number of arguments for a subroutine call at runtime.
However the C faq says;
	15.12:  How can I write a function which takes a variable number of
        arguments and passes them to some other function (which takes a
        variable number of arguments)?
	A:      In general, you cannot.  Ideally, you should provide a version
        of that other function which accepts a va_list pointer
        (analogous to vfprintf(); see question 15.5 above).  If the
        arguments must be passed directly as actual arguments, or if you
        do not have the option of rewriting the second function to
        accept a va_list (in other words, if the second, called function
        must accept a variable number of arguments, not a va_list), no
        portable solution is possible.  (The problem could perhaps be
        solved by resorting to machine-specific assembly language; see
        also question 15.13 below.)
	15.13:  How can I call a function with an argument list built up at run
        time?
	A:      There is no guaranteed or portable way to do this. . . .

As for answer 15.12, I don't have control over the subroutines I am 
calling, so I can't use varargs.  Both answers 15.12 and 15.13 are
unsatisfactory since clearly many people have already solved
this problem (eg. AVS, Iris Explorer, and perhaps even TK (don't really
have much experience in that case))  I've come up with a couple of 
working solutions myself, but I find them to be bletcherous abuses of
C syntax and general programming sanity.  My methods also have the 
restrictions that all arguments be of the same byte length.  
Packing args with variable byte-length would be preferred,
but fixed length gets me pretty far.  

Has anyone come up with a saner, more portable method for generating
subroutines calls with a variable number of arguments at runtime?

Here's an example demonstrating a couple of the methods for doing this
which I don't particularly like.

-john

#include <stdio.h>
typedef void(*funcproto)(int,int,int,int);
typedef int farg;  /* also played with (void *) for argtypes, but
			it ended up being unnecessarily painful */

/* typedefs for for one of the brain damaged conditional methods for
	  generating calls */ 
typedef void(*sub0)();
typedef void(*sub1)(int);
typedef void(*sub2)(int,int);
typedef void(*sub3)(int,int,int);
typedef void(*sub4)(int,int,int,int);
void TestSub(int a,int b,int *c)
{
	(*c)=a+b;
	printf("got a=%u + b=%u ==> c address=%u value=%u\n",a,b,(int)c,*c);
}

void CallConvert(funcproto sub,farg *args,int nargs)
{
	printf("nargs=%u\n",nargs);
	/*  --This method is most compact in representation, but
			if I want to allow a reasonable number of parameters
			it will exact a pretty large calling overhead
			regardless of the number of parameters.
		--This works for little-endian machines (or at least so far
		  little-endian machines appear to push params on the
		  call stack/regs in this order. 
		  (tested on HP-PA, SGI-MIPS, SUN-SPARC)
	sub((nargs>0)?args[0]:0,(nargs>1)?args[1]:0,
		(nargs>2)?args[2]:0,(nargs>3)?args[3]:0);
	*/
	/*  --The big-endian version of the above method.
	(yeah, so nargs-(<const>-nargs) could be reduced to nargs<<1-<const>
	 at the expense of a little extra obfuscation... oh well...)
		(tested on Macintosh)
	
sub((nargs>3)?args[nargs-(7-nargs)]:0,(nargs>2)?args[nargs-(6-nargs)]:0,
		(nargs>1)?args[nargs-(5-nargs)]:0,(nargs>0)?args[nargs-(4-nargs)]:0);
	*/
	/*  --This version works fine with any architecture, but it
			costs a whole lot more per argument when you get to longer
	  argument lists because most
			compilers implement switch in the stupidest possible
			manner (instead of a jump table which would be the
			most naturally efficient mapping). 
	*/
	switch(nargs)
	{
		case 0: ((sub0)sub)(); break;
		case 1: ((sub1)sub)(args[0]); break;
		case 2: ((sub2)sub)(args[0],args[1]); break;
		case 3: ((sub3)sub)(args[0],args[1],args[2]); break;
		case 4: ((sub4)sub)(args[0],args[1],args[2],args[3]); break;
	}
}

int main()
{
	farg args[3];
	int nargs=3,c;
	args[0]=2;
	args[1]=3;
	args[2]=(int)(&c);
	printf("address of c=%u\n",(int)(&c));
	printf("c=%u\n", c );
	CallConvert((funcproto)TestSub,args,nargs);
	printf("c=%u\n",c);
 return 1;
}
Technical Details
Message-ID: <4gsaai$41m@solutions.solon.com>
Path: arc1-ca.pugleaf.net!solon.com!not-for-mail

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!solon.com!not-for-mail
From: John Shalf <jshalf@ncsa.uiuc.edu>
Newsgroups: comp.lang.c.moderated
Subject: Variable param for non-vararg subr. calls
Date: 26 Feb 1996 06:50:26 -0600
Organization: NCSA
Sender: clc@solutions.solon.com
Approved: clc@solutions.solon.com
Message-ID: <4gsaai$41m@solutions.solon.com>
NNTP-Posting-Host: solutions.solon.com
X-Mailer: Mozilla 1.12(Macintosh; I; 68K)
X-URL: news://news.cso.uiuc.edu/comp.lang.c.moderated