| How to extend C programs with Guile | ||
|---|---|---|
| <<< Previous | Functions II | Next >>> |
In C, one can create a function with a variable number of input arguments. The most well known example would be printf, which takes one required parameter, and may also optionally be passed one or more additional parameters. For printf the optional parameter is a format string, and the addition parameters are variables whose values are to be inserted into the format string. When writing a function with variable numbers of parameters in C, the macros va_start, va_arg, and va_end are used to unpack the parameters which the compiler has placed in a va_list.
A C function for use with Guile, also known as a gsubr, can also be created to take a variable number of parameters. When declared, the gsubr has a final argument that will contain the optional parameters. This final argument is a Guile list pack in an SCM, instead of a va_list.
As described in the section called Manually Creating a C Function for Guile in the chapter called Functions I>, the basic process for creating a new Guile function is to write a C function that takes zero or more SCMas input and then returns an SCM, and then to register it for use with Guile using the function scm_c_define_gsubr.
The function scm_c_define_gsubr takes the C function func and registers it as a Guile function with the name name. The function's name in Guile (name) and its name in C (func) do not have to be the same. req is the function's number of required input parameters. opt is its number of optional parameters. rst is a flag that indicates if the function takes a variable number of inputs.
So a function that should take one required and one or more additional arguments will have req = 1, opt = 0, and res = 1. The gsubr will take two input parameters, the first one is the required parameter, the second one is a list of one or more additional parameters.
Consider the following example. A gsubr function is created that takes a variable-sized list of numbers and returns its average. The function is registered using scm_c_define_gsubr so that it is available for use in the script script.scm.
#include <stdio.h>
#include <string.h>
#include <libguile.h>
SCM scm_average_list (SCM s_num_list);
int main(int argc, char **argv)
{
/* initialize Guile */
scm_init_guile();
/* Register the new C-Guile functions */
scm_c_define_gsubr
("average-list", 0, 0, 1, (SCM (*)()) scm_average_list);
/* Load the library of Guile functions */
scm_c_primitive_load("script.scm");
return 0;
}
SCM scm_average_list (SCM s_num_list)
{
SCM s_element;
int length;
int i;
double sum;
/* Check that the input is a list */
SCM_ASSERT (SCM_NFALSEP (scm_list_p (s_num_list)),
s_num_list,
SCM_ARG1,
"average-list");
length = scm_num2int(scm_length(s_num_list), 0, "scm_average_list()");
if (length == 0) {
return scm_double2num(0.0);
} else {
sum = 0.0;
for (i = 0; i < length; i ++) {
s_element = scm_list_ref(s_num_list, scm_int2num(i));
sum = sum + scm_num2double (s_element, 0, "average-list");
}
}
return (scm_double2num(sum / (double)length));
}
|
The function might be called like this...
(display (average-list 1 2 3 4 5))
(newline)
|
| <<< Previous | Home | Next >>> |
| Functions II | Up | Custom data types (SMOBs) |