Thousands of changes to correct incorrect HTML. HTML is now valid (transitional 4.01).
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@6074 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
7cb896a5f4
commit
aa4d1d907d
31 changed files with 6754 additions and 4801 deletions
|
|
@ -5,18 +5,18 @@
|
|||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<a name="n1"></a><H1>11 Variable Length Arguments</H1>
|
||||
<H1><a name="Varargs"></a>13 Variable Length Arguments</H1>
|
||||
<!-- INDEX -->
|
||||
<ul>
|
||||
<li><a href="#n2">Introduction</a>
|
||||
<li><a href="#n3">The Problem</a>
|
||||
<li><a href="#n4">Default varargs support</a>
|
||||
<li><a href="#n5">Argument replacement using %varargs</a>
|
||||
<li><a href="#n6">Varargs and typemaps</a>
|
||||
<li><a href="#n7">Varargs wrapping with libffi</a>
|
||||
<li><a href="#n8">Wrapping of va_list</a>
|
||||
<li><a href="#n9">C++ Issues</a>
|
||||
<li><a href="#n10">Discussion</a>
|
||||
<li><a href="#Varargs_nn2">Introduction</a>
|
||||
<li><a href="#Varargs_nn3">The Problem</a>
|
||||
<li><a href="#Varargs_nn4">Default varargs support</a>
|
||||
<li><a href="#Varargs_nn5">Argument replacement using %varargs</a>
|
||||
<li><a href="#Varargs_nn6">Varargs and typemaps</a>
|
||||
<li><a href="#Varargs_nn7">Varargs wrapping with libffi</a>
|
||||
<li><a href="#Varargs_nn8">Wrapping of va_list</a>
|
||||
<li><a href="#Varargs_nn9">C++ Issues</a>
|
||||
<li><a href="#Varargs_nn10">Discussion</a>
|
||||
</ul>
|
||||
<!-- INDEX -->
|
||||
|
||||
|
|
@ -25,18 +25,19 @@
|
|||
<b>(a.k.a, "The horror. The horror.")</b>
|
||||
|
||||
<p>
|
||||
|
||||
This chapter describes the problem of wrapping functions that take a
|
||||
variable number of arguments. For instance, generating wrappers for
|
||||
the C <tt>printf()</tt> family of functions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This topic is sufficiently advanced to merit its own chapter. In
|
||||
fact, support for varargs is an often requested feature that was first
|
||||
added in SWIG-1.3.12. Most other wrapper generation tools have
|
||||
wisely chosen to avoid this issue.
|
||||
</p>
|
||||
|
||||
<a name="n2"></a><H2>11.1 Introduction</H2>
|
||||
<H2><a name="Varargs_nn2"></a>13.1 Introduction</H2>
|
||||
|
||||
|
||||
Some C and C++ programs may include functions that accept a variable
|
||||
|
|
@ -74,6 +75,7 @@ list of pointers into which return values are placed. However, variable
|
|||
length arguments are also sometimes used to write functions that accept a
|
||||
NULL-terminated list of pointers. A good example of this would
|
||||
be a function like this:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -122,7 +124,7 @@ List make_list(const char *s, ...) {
|
|||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<a name="n3"></a><H2>11.2 The Problem</H2>
|
||||
<H2><a name="Varargs_nn3"></a>13.2 The Problem</H2>
|
||||
|
||||
|
||||
Generating wrappers for a variable length argument function presents a
|
||||
|
|
@ -138,10 +140,12 @@ type <tt>va_list</tt>, this is something entirely different. You
|
|||
can't take a <tt>va_list</tt> structure and pass it in place of the
|
||||
variable length arguments to another varargs function. It just
|
||||
doesn't work.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The reason this doesn't work has to do with the way that function
|
||||
calls get compiled. For example, suppose that your program has a function call like this:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -159,6 +163,7 @@ frame followed by a call to <tt>printf()</tt>.
|
|||
<p>
|
||||
In contrast, suppose you attempted to make some kind of wrapper around
|
||||
<tt>printf()</tt> using code like this:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -188,6 +193,7 @@ worse, you won't know the types and sizes of arguments until run-time
|
|||
as well. Needless to say, there is no obvious way to make the C
|
||||
compiler generate code for a function call involving an unknown number
|
||||
of arguments of unknown types.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In theory, it <em>is</em> possible to write a wrapper that does the right thing.
|
||||
|
|
@ -195,6 +201,7 @@ However, this involves knowing the underlying ABI for the target platform and la
|
|||
as well as writing special purpose code that manually constructed the call stack before
|
||||
making a procedure call. Unfortunately, both of these tasks require the use of inline
|
||||
assembly code. Clearly, that's the kind of solution you would much rather avoid.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
With this nastiness in mind, SWIG provides a number of solutions to the varargs
|
||||
|
|
@ -202,8 +209,9 @@ wrapping problem. Most of these solutions are compromises that provide limited
|
|||
varargs support without having to resort to assembly language. However, SWIG
|
||||
can also support real varargs wrapping (with stack-frame manipulation) if you
|
||||
are willing to get hands dirty. Keep reading.
|
||||
</p>
|
||||
|
||||
<a name="n4"></a><H2>11.3 Default varargs support</H2>
|
||||
<H2><a name="Varargs_nn4"></a>13.3 Default varargs support</H2>
|
||||
|
||||
|
||||
When variable length arguments appear in an interface, the default
|
||||
|
|
@ -239,14 +247,14 @@ instance, you could make function calls like this (in Python):
|
|||
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> traceprintf("Hello World")
|
||||
>>> traceprintf("Hello %s. Your number is %d\n" % (name, num))
|
||||
>>> traceprintf("Hello World")
|
||||
>>> traceprintf("Hello %s. Your number is %d\n" % (name, num))
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
Notice how string formatting is being done in Python instead of C.
|
||||
|
||||
<a name="n5"></a><H2>11.4 Argument replacement using %varargs</H2>
|
||||
<H2><a name="Varargs_nn5"></a>13.4 Argument replacement using %varargs</H2>
|
||||
|
||||
|
||||
Instead of dropping the variable length arguments, an alternative approach is to replace
|
||||
|
|
@ -292,13 +300,15 @@ known. When replicated argument replacement is used, at least one extra
|
|||
argument is added to the end of the arguments when making the function call.
|
||||
This argument serves as a sentinel to make sure the list is properly terminated.
|
||||
It has the same value as that supplied to the <tt>%varargs</tt> directive.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Argument replacement is not as useful when working with functions that accept
|
||||
mixed argument types such as <tt>printf()</tt>. Providing general purpose
|
||||
wrappers to such functions presents special problems (covered shortly).
|
||||
</p>
|
||||
|
||||
<a name="n6"></a><H2>11.5 Varargs and typemaps</H2>
|
||||
<H2><a name="Varargs_nn6"></a>13.5 Varargs and typemaps</H2>
|
||||
|
||||
|
||||
Variable length arguments may be used in typemap specifications. For example:
|
||||
|
|
@ -326,6 +336,7 @@ default behavior of SWIG is to pass the <tt>void *</tt> value as an argument to
|
|||
the function. Therefore, you could use the pointer to hold a valid argument value if you wanted.
|
||||
<p>
|
||||
To illustrate, here is a safer version of wrapping <tt>printf()</tt> in Python:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -369,6 +380,7 @@ The next example illustrates a more advanced kind of varargs typemap.
|
|||
Disclaimer: this requires special support in the target language module and is not
|
||||
guaranteed to work with all SWIG modules at this time. It also starts to illustrate
|
||||
some of the more fundamental problems with supporting varargs in more generality.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a typemap is defined for any form of <tt>(...)</tt>, many SWIG
|
||||
|
|
@ -380,6 +392,7 @@ However, suppose that you wanted to create a Python wrapper for the
|
|||
<tt>execlp()</tt> function shown earlier. To do this using a typemap
|
||||
instead of using <tt>%varargs</tt>, you might first write a typemap
|
||||
like this:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -388,7 +401,7 @@ like this:
|
|||
int argc;
|
||||
for (i = 0; i < 10; i++) args[i] = 0;
|
||||
argc = PyTuple_Size(varargs);
|
||||
if (argc > 10) {
|
||||
if (argc > 10) {
|
||||
PyErr_SetString(PyExc_ValueError,"Too many arguments");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -427,15 +440,16 @@ this:
|
|||
int execlp(const char *path, const char *arg, ...);
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
|
||||
<p>
|
||||
This patches everything up and creates a function that more or less
|
||||
works. However, don't try explaining this to your coworkers unless
|
||||
you know for certain that they've had several cups of coffee. If you
|
||||
really want to elevate your guru status and increase your job
|
||||
security, continue to the next section.
|
||||
</p>
|
||||
|
||||
<a name="n7"></a><H2>11.6 Varargs wrapping with libffi</H2>
|
||||
<H2><a name="Varargs_nn7"></a>13.6 Varargs wrapping with libffi</H2>
|
||||
|
||||
|
||||
All of the previous examples have relied on features of SWIG that are
|
||||
|
|
@ -446,7 +460,7 @@ with a fixed number of arguments of known types. In many cases, this
|
|||
works perfectly fine. However, if you want more generality than this,
|
||||
you need to bring out some bigger guns.
|
||||
|
||||
<P>
|
||||
<p>
|
||||
One way to do this is to use a special purpose library such as libffi
|
||||
(<a
|
||||
href="http://sources.redhat.com/libffi/">http://sources.redhat.com/libffi</a>).
|
||||
|
|
@ -454,12 +468,14 @@ libffi is a library that allows you to dynamically construct
|
|||
call-stacks and invoke procedures in a relatively platform independent
|
||||
manner. Details about the library can be found in the libffi
|
||||
distribution and are not repeated here.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To illustrate the use of libffi, suppose that you <em>really</em> wanted to create a
|
||||
wrapper for <tt>execlp()</tt> that accepted <em>any</em> number of
|
||||
arguments. To do this, you might make a few adjustments to the previous
|
||||
example. For example:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -501,21 +517,21 @@ example. For example:
|
|||
args = (char **) arg3;
|
||||
|
||||
/* Set up path parameter */
|
||||
types[0] = &ffi_type_pointer;
|
||||
values[0] = &arg1;
|
||||
types[0] = &ffi_type_pointer;
|
||||
values[0] = &arg1;
|
||||
|
||||
/* Set up first argument */
|
||||
types[1] = &ffi_type_pointer;
|
||||
values[1] = &arg2;
|
||||
types[1] = &ffi_type_pointer;
|
||||
values[1] = &arg2;
|
||||
|
||||
/* Set up rest of parameters */
|
||||
for (i = 0; i <= vc; i++) {
|
||||
types[2+i] = &ffi_type_pointer;
|
||||
values[2+i] = &args[i];
|
||||
types[2+i] = &ffi_type_pointer;
|
||||
values[2+i] = &args[i];
|
||||
}
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, vc+3,
|
||||
&ffi_type_uint, types) == FFI_OK) {
|
||||
ffi_call(&cif, (void (*)()) execlp, &result, values);
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, vc+3,
|
||||
&ffi_type_uint, types) == FFI_OK) {
|
||||
ffi_call(&cif, (void (*)()) execlp, &result, values);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
|
||||
free(types);
|
||||
|
|
@ -541,6 +557,7 @@ first place?!?" Obviously, those are questions you'll have to answer for yourse
|
|||
|
||||
<p>
|
||||
As a more extreme example of libffi, here is some code that attempts to wrap <tt>printf()</tt>,
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -604,32 +621,32 @@ As a more extreme example of libffi, here is some code that attempts to wrap <tt
|
|||
args = (vtype *) arg2;
|
||||
|
||||
/* Set up fmt parameter */
|
||||
types[0] = &ffi_type_pointer;
|
||||
values[0] = &arg1;
|
||||
types[0] = &ffi_type_pointer;
|
||||
values[0] = &arg1;
|
||||
|
||||
/* Set up rest of parameters */
|
||||
for (i = 0; i < vc; i++) {
|
||||
switch(args[i].type) {
|
||||
case VT_INT:
|
||||
types[1+i] = &ffi_type_uint;
|
||||
values[1+i] = &args[i].val.ivalue;
|
||||
types[1+i] = &ffi_type_uint;
|
||||
values[1+i] = &args[i].val.ivalue;
|
||||
break;
|
||||
case VT_DOUBLE:
|
||||
types[1+i] = &ffi_type_double;
|
||||
values[1+i] = &args[i].val.dvalue;
|
||||
types[1+i] = &ffi_type_double;
|
||||
values[1+i] = &args[i].val.dvalue;
|
||||
break;
|
||||
case VT_POINTER:
|
||||
types[1+i] = &ffi_type_pointer;
|
||||
values[1+i] = &args[i].val.pvalue;
|
||||
types[1+i] = &ffi_type_pointer;
|
||||
values[1+i] = &args[i].val.pvalue;
|
||||
break;
|
||||
default:
|
||||
abort(); /* Whoa! We're seriously hosed */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, vc+1,
|
||||
&ffi_type_uint, types) == FFI_OK) {
|
||||
ffi_call(&cif, (void (*)()) printf, &result, values);
|
||||
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, vc+1,
|
||||
&ffi_type_uint, types) == FFI_OK) {
|
||||
ffi_call(&cif, (void (*)()) printf, &result, values);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
|
||||
free(types);
|
||||
|
|
@ -651,10 +668,10 @@ Much to your amazement, it even seems to work if you try it:
|
|||
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> import example
|
||||
>>> example.printf("Grade: %s %d/60 = %0.2f%%\n", "Dave", 47, 47.0*100/60)
|
||||
>>> import example
|
||||
>>> example.printf("Grade: %s %d/60 = %0.2f%%\n", "Dave", 47, 47.0*100/60)
|
||||
Grade: Dave 47/60 = 78.33%
|
||||
>>>
|
||||
>>>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
|
|
@ -662,7 +679,7 @@ Of course, there are still some limitations to consider:
|
|||
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> example.printf("la de da de da %s", 42)
|
||||
>>> example.printf("la de da de da %s", 42)
|
||||
Segmentation fault (core dumped)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
|
@ -674,7 +691,7 @@ module, we used the special <tt>varargs</tt> variable to get these arguments. M
|
|||
provide an argument number for the first extra argument. This can be used to index into an array of passed arguments to get
|
||||
values. Please consult the chapter on each language module for more details.
|
||||
|
||||
<a name="n8"></a><H2>11.7 Wrapping of va_list</H2>
|
||||
<H2><a name="Varargs_nn8"></a>13.7 Wrapping of va_list</H2>
|
||||
|
||||
|
||||
Closely related to variable length argument wrapping, you may encounter functions that accept a parameter
|
||||
|
|
@ -694,7 +711,7 @@ of a <tt>va_list</tt> structure are closely tied to the underlying
|
|||
call-stack. It's not clear that exporting a <tt>va_list</tt> would
|
||||
have any use or that it would work at all.
|
||||
|
||||
<a name="n9"></a><H2>11.8 C++ Issues</H2>
|
||||
<H2><a name="Varargs_nn9"></a>13.8 C++ Issues</H2>
|
||||
|
||||
|
||||
Wrapping of C++ member functions that accept a variable number of
|
||||
|
|
@ -735,17 +752,19 @@ invocation might require a table lookup to obtain the proper function address
|
|||
(although you might be able to obtain an address by casting a bound
|
||||
pointer to a pointer to function as described in the C++ ARM section
|
||||
18.3.4).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you do decide to change the underlying action code, be aware that SWIG
|
||||
always places the <tt>this</tt> pointer in <tt>arg1</tt>. Other arguments
|
||||
are placed in <tt>arg2</tt>, <tt>arg3</tt>, and so forth. For example:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
%feature("action") Foo::bar {
|
||||
...
|
||||
result = arg1->bar(arg2, arg3, etc.);
|
||||
result = arg1->bar(arg2, arg3, etc.);
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
|
@ -755,7 +774,7 @@ Given the potential to shoot yourself in the foot, it is probably easier to reco
|
|||
design or to provide an alternative interface using a helper function than it is to create a
|
||||
fully general wrapper to a varargs C++ member function.
|
||||
|
||||
<a name="n10"></a><H2>11.9 Discussion</H2>
|
||||
<H2><a name="Varargs_nn10"></a>13.9 Discussion</H2>
|
||||
|
||||
|
||||
This chapter has provided a number of techniques that can be used to address the problem of variable length
|
||||
|
|
@ -770,6 +789,7 @@ are a number of subtle aspects of the solution to consider--mostly concerning th
|
|||
problem has been decomposed. First, the example is structured in a way that tries to maintain separation
|
||||
between wrapper-specific information and the declaration of the function itself. The idea here is that
|
||||
you might structure your interface like this:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -823,8 +843,9 @@ carefully read the section "A7.3.2 Function Calls" in Kernighan and
|
|||
Ritchie and make sure you fully understand the parameter passing conventions used for varargs.
|
||||
Also, be aware of the platform dependencies and reliability issues that
|
||||
this will introduce. Good luck.
|
||||
</p>
|
||||
|
||||
<p><hr>
|
||||
<hr>
|
||||
|
||||
<address>SWIG 1.3 - Last Modified : March 24, 2002</address>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue