Argumentos de Salida en XS

En el siguiente ejemplo proveemos un resolutor de ecuaciones de primer y segundo grado. La estructura de directorios - creada con h2xs -A -n CodeAndOutput es como sigue:
lhp@nereida:~/projects/perl/src/XSUB/CodeAndOutput$ tree
.
|-- Changes
|-- CodeAndOutput.xs
|-- MANIFEST
|-- Makefile.PL
|-- README
|-- lib
|   `-- CodeAndOutput.pm
|-- main.c
|-- ppport.h
|-- solve.c
|-- t
|   `-- CodeAndOutput.t
`-- use.pl
Los parámetros en las líneas 15 y 16 son inicializados a NO_INIT. La palabra clave NO_INIT indica que el parámetro no es de entrada y que su valor inicial no importa. El compilador xsubpp habitualmente genera código para la lectura de todos los parámetros desde la pila de argumentos Perl para asignarselos a las correspondientes variables C. La palabra clave NO_INIT le dice a xsubpp que tales párametros pueden ser obviados para esta operación.

El uso de punteros en C en una declaración de función puede significar - desde el punto de vista de la entrada-salida de dicha función - cosas distintas. Por ejemplo, en la declaración

   bool string_looks_like_as_a-number(char *s)
el parámetro s es (un puntero a un array de caracteres) de entrada mientras que el parámetro c en
   bool make_char_uppercase(char *c)
es (un puntero a un carácter) de salida. Para distinguir estas dos formas de uso XSUB requiere que las declaraciones de prototipo XSUB sean de la forma:

             char *s
             char &c
es por esta razón que los parámetros x1 y x2 que contendrán las soluciones a la ecuación son declarados como double &x1 y double &x2.

La palabra clave CODE usada en la línea 17 indica código para el cuerpo de la XSUB. La variable RETVAL es creada automáticamente por el compilador xsubpp: su valor será usado como valor de retorno de la función.

lhp@nereida:~/projects/perl/src/XSUB/CodeAndOutput$ cat -n CodeAndOutput.xs
 1  #include "EXTERN.h"
 2  #include "perl.h"
 3  #include "XSUB.h"
 4
 5  #include "ppport.h"
 6
 7
 8  MODULE = CodeAndOutput          PACKAGE = CodeAndOutput
 9
10  int
11  solveeq2(a, b, c, x1, x2)
12      double a
13      double b
14      double c
15      double &x1 = NO_INIT
16      double &x2 = NO_INIT
17    CODE:
18    {
19
20      if (a == 0) {
21        if (b == 0) {
22          if (c != 0) {
23            RETVAL = 0;
24          }
25          RETVAL = -1; /* infinitas soluciones */
26        }
27        x1 = -c/b;
28        RETVAL = 1;
29      }
30
31      double d = b*b -4*a*c;
32      if (d >= 0) {
33        d = sqrt(d);
34        x1 = (-b + d)/(2*a);
35        x2 = (-b - d)/(2*a);
36        RETVAL = 2;
37      }
38      RETVAL = 0;
39    }
40  OUTPUT:
41    RETVAL
42    x1
43    x2
La palabra clave OUTPUT indica que los parámetros que siguen deberán ser actualizados cuando la XSUB termina (x1 y x2 en este ejemplo) o que ciertos valores deben ser retornados por la función (RETVAL en este ejemplo. RETVAL no se retorna automáticamente is existe una sección CODE en la XSUB).

El siguiente código muestra un programa cliente y una ejecución:

lhp@nereida:~/projects/perl/src/XSUB/CodeAndOutput$ cat -n use.pl
  1  #!/usr/local/bin/perl -w
  2  use strict;
  3  use blib;
  4  use CodeAndOutput;
  5
  6  my ($x1, $x2);
  7
  8  CodeAndOutput::solveeq2(1, -3, 2, $x1, $x2);
  9
 10  print "$x1 $x2\n";
lhp@nereida:~/projects/perl/src/XSUB/CodeAndOutput$ use.pl
2 1

Casiano Rodríguez León
2010-03-22