⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 invvarargs.19890604.html

📁 this is a mirrored site c-faq. thought might need offline
💻 HTML
字号:
<html><!-- Mirrored from c-faq.com/varargs/invvarargs.19890604.html by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 08:03:00 GMT --><head><title>"inverse varargs problem", take 1</title></head><body><p>[This article was originally posted on June 4, 1989.I have altered the presentation slightly for this web page.]<p>From: scs@adam.pika.mit.edu (Steve Summit)<br>Newsgroups: comp.unix.wizards,comp.lang.c<br>Subject: Re: Needed:  A (Portable) way of setting up the arg stack<br>Keywords: 1/varargs, callg<br>Message-ID: &lt;11830@bloom-beacon.MIT.EDU&gt;<br>Date: 4 Jun 89 16:43:52 GMT<br>References: &lt;708@mitisft.Convergent.COM&gt; &lt;32208@apple.Apple.COM&gt; &lt;10354@smoke.BRL.MIL&gt;<p>In article &lt;708@mitisft.Convergent.COM&gt; Gregory Kemnitz writes:<br>&gt;I need to know how (or if) *NIX (System V.3) has the ability to let<br>&gt;a stack of arguments be set for a function before it is called.  I<br>&gt;have several hundred pointers to functions which are called from one<br>&gt;place, and each function has different numbers of arguments.<p>A nice problem.  Doug Gwyn's suggestion is the right one, formaximum portability, but constrains the form of the calledsubroutines and also any calls that do not go through the"inverse varargs mechanism."  (That is, you can't really call thesubroutines in question without building the little argumentvector.)<p>For transparency (at some expense in portability) I use a routineI call "<TT>callg</TT>," named after the VAX instruction of the same name.(This is equivalent to Peter Desnoyers' "<TT>va_call</TT>" routine; inretrospect, I like his name better.)<p><TT>va_call</TT> can be implemented in one line of assembly language onthe VAX; it typically requires ten or twenty lines on othermachines, to copy the arguments from the vector to the real stack(or wherever arguments are really passed).  I have implementationsfor the PDP11, NS32000, 68000, and 80x86.  (This is a machinespecific problem, not an operating system specific problem.)  Aroutine such as <TT>va_call</TT> <em>must</em> be written in assembly language; itis one of the handful of functions I know of that cannot possiblybe written in C.<p>Not all machines use a stack; some use register passing or otherconventions.  For maximum portability, then, the interface to aroutine like <TT>va_call</TT> should allow the type of each argument to beexplicitly specified, as well as hiding the details of theargument vector construction.  I have been contemplating aninterface similar to that illustrated by the following example:<p><pre><TT>	#include "varargs2.h"	extern printf();	main()	{	va_stack(stack, 10);	/* declare vector which holds up to 10 args */	va_push(stack, "%d %f %s\n", char *);	va_push(stack, 12, int);	va_push(stack, 3.14, double);	va_push(stack, "Hello, world!", char *);	va_call(printf, stack);	}</TT></pre><p>Note that this calls the standard <TT>printf</TT>; <TT>printf</TT> need take nospecial precautions, and indeed cannot necessarily tell that ithas not been called normally.  (This is what I meant by"transparency.")<p>On a "conventional," stack-based machine, <TT>va_stack</TT> would declarean array of 10 <TT>int</TT>s (assuming that <TT>int</TT> is the machine's naturalword size) and <TT>va_push</TT> would copy words to it using pointermanipulations analogous to those used by the <TT>va_arg</TT> macro in thecurrent <TT>varargs</TT> and <TT>stdarg</TT> implementations.  (Note that "declarevector which holds up to 10 args" is therefore misleading; the vectorholds up to 10 words, and it is up to the programmer to leaveenough slop for multi-word types such as <TT>long</TT> and <TT>double</TT>.  Thedistinction between a "word" and an "argument" is the one thatalways comes up when someone suggests supplying a <TT>va_nargs()</TT>macro; let's not start that discussion again.)<p>For a register-passing machine, the choice of registers maydepend on the types of the arguments.  For this reason, theinterface must allow the type information to be retained in theargument vector for inspection by the <TT>va_call</TT> routine.  Thiswould be easier to be implement if manifest constants were used,instead of C type names:<p><pre><TT>	va_push(stack, 12, VA_INT);	va_push(stack, 3.14, VA_DOUBLE);	va_push(stack, "Hello, world!", VA_POINTER);</TT></pre><p>Since it would be tricky to "switch" on these constants insidethe <TT>va_push</TT> macro to decide how many words of the vector to setaside, separate push macros might be preferable:<p><pre><TT>	va_push_int(stack, 12);	va_push_double(stack, 3.14);	va_push_pointer(stack, "Hello, world!");</TT></pre><p>(This option has the additional advantage over the single <TT>va_push</TT>in that it does not require that the second macro argument be ofvariable type.)  There is still a major difficulty here, however,in that one cannot assume the existence of a single kind ofpointer.<p>For the "worst" machines, the full generality of C type names (asin the first example) would probably be required.  Unfortunately,to do everything with type names you might want to do, you haveto handle them specially in the compiler.  (On the other hand,the machines that would have trouble with <TT>va_push</TT> are probablythe same ones that already have to have the <TT>varargs</TT> or <TT>stdarg</TT>mechanisms recognized by the compiler.)<p>Lest you think that <TT>va_call</TT>, if implementable, solves the wholeproblem, don't let your breath out yet: what should the returnvalue be?  In the most general case, the routines being indirectlycalled might return different types.  The return value of <TT>va_call</TT>would not, so to speak, be representable in closed form.<p>This last wrinkle (variable return type on top of variablearguments passed) is at the heart of a C interpreter that allowsintermixing of interpreted and compiled code.  I know how Isolved it; I'd be curious to know how Saber C solves it.  (Isolved it with two more assembly language routines, alsounimplementable in C.  A better solution, to half of the problem,anyway, would be to to provide a third argument, a union pointerof some kind, to <TT>va_call</TT> for storing the return value.)<p>I just whipped together <a href="#implementation">an implementation</a> of the first example,which I have appended for your edification and amusement, as longas you have a VAX.<p><address><a href="http://www.eskimo.com/~scs/">Steve Summit</a><br><a href="mailto:scs@eskimo.com">scs@eskimo.com</a></address><p><a name="implementation">[The "implementation" consists of three files:<br><a href="pf.c">pf.c</a><a href="varargs2.h">varargs2.h</a><a href="va_call.t">va_call.s</a>]</body><!-- Mirrored from c-faq.com/varargs/invvarargs.19890604.html by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 08:03:05 GMT --></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -