InglésFrancésEspañol

icono de página de OnWorks

perlcall - Online en la nube

Ejecute perlcall en el proveedor de alojamiento gratuito de OnWorks sobre Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS

Este es el comando perlcall que se puede ejecutar en el proveedor de alojamiento gratuito de OnWorks utilizando una de nuestras múltiples estaciones de trabajo en línea gratuitas, como Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS.

PROGRAMA:

NOMBRE


perlcall - Convenciones de llamadas de Perl desde C

DESCRIPCIÓN


El propósito de este documento es mostrarle cómo llamar subrutinas Perl directamente desde C,
es decir, como escribir devoluciones de llamada.

Aparte de discutir la interfaz C proporcionada por Perl para escribir devoluciones de llamada, el documento
utiliza una serie de ejemplos para mostrar cómo funciona realmente la interfaz en la práctica. En
Además, se cubren algunas técnicas para codificar devoluciones de llamada.

Los ejemplos en los que son necesarias devoluciones de llamada incluyen

· Un gestor de errores

Ha creado una interfaz XSUB para la API C de una aplicación.

Una característica bastante común en las aplicaciones es permitirle definir una función C que
se llamará siempre que ocurra algo desagradable. Lo que nos gustaría es poder
especifique una subrutina de Perl que se llamará en su lugar.

· Un programa impulsado por eventos

El ejemplo clásico de donde se usan devoluciones de llamada es cuando se escribe un evento impulsado
programa, como para una aplicación X11. En este caso, registra funciones para ser
se llama siempre que ocurren eventos específicos, por ejemplo, se presiona un botón del mouse, el cursor
se mueve a una ventana o se selecciona un elemento del menú.

Aunque las técnicas descritas aquí son aplicables al incrustar Perl en un programa C,
este no es el objetivo principal de este documento. Hay otros detalles que deben ser
considerados y son específicos para incrustar Perl. Para obtener detalles sobre la incrustación de Perl en C, consulte
perplejo

Antes de lanzarse de cabeza al resto de este documento, sería una buena idea
idea de haber leído los dos documentos siguientes: perlxs y perlguts.

EL LLAMAR_ Las funciones


Aunque estas cosas son más fáciles de explicar con ejemplos, primero debe conocer algunas
definiciones importantes.

Perl tiene una serie de funciones en C que le permiten llamar a subrutinas de Perl. Ellos son

I32 call_sv (SV * sv, indicadores I32);
I32 call_pv (char * subnombre, indicadores I32);
I32 call_method (char * methname, indicadores I32);
I32 call_argv (char * subnombre, indicadores I32, char ** argv);

La función clave es llamar_sv. Todas las demás funciones son envoltorios bastante simples que
facilitan la llamada a subrutinas de Perl en casos especiales. Al final del día lo harán
todas las llamadas llamar_sv para invocar la subrutina Perl.

Todos los llamar_* Las funciones tienen un parámetro "banderas" que se utiliza para pasar una máscara de bits de
opciones a Perl. Esta máscara de bits opera de manera idéntica para cada una de las funciones. El
Los ajustes disponibles en la máscara de bits se describen en "VALORES DE BANDERA".

Cada una de las funciones se discutirá a continuación.

llamar_sv
llamar_sv toma dos parámetros. El primero, "sv", es un SV *. Esto le permite especificar
la subrutina Perl que se llamará como una cadena C (que primero se ha convertido
a un SV) o una referencia a una subrutina. La sección, Gracias a llamar_sv, muestra como tu
puede hacer uso de llamar_sv.

llamada_pv
La función, llamada_pv, es parecido a llamar_sv excepto que espera que su primer parámetro
ser un C char * que identifica la subrutina Perl que desea llamar, por ejemplo,
"call_pv (" fred ", 0)". Si la subrutina que desea llamar está en otro paquete, simplemente
incluya el nombre del paquete en la cadena, por ejemplo, "pkg :: fred".

método_de_llamada
La función método_de_llamada se usa para llamar a un método desde una clase Perl. El parámetro
"methname" corresponde al nombre del método que se va a llamar. Tenga en cuenta que la clase
al que pertenece el método se pasa en la pila de Perl en lugar de en el parámetro
lista. Esta clase puede ser el nombre de la clase (para un método estático) o un
referencia a un objeto (para un método virtual). Consulte perlobj para obtener más información sobre
métodos estáticos y virtuales y "Usando call_method" para un ejemplo de cómo usar
método_de_llamada.

llamada_argv
llamada_argv llama a la subrutina Perl especificada por la cadena C almacenada en el "subnombre"
parámetro. También toma el parámetro habitual "banderas". El parámetro final, "argv",
consiste en una lista terminada en NULL de cadenas C que se pasarán como parámetros al
Subrutina Perl. Ver Gracias a llamada_argv.

Todas las funciones devuelven un número entero. Este es un recuento de la cantidad de artículos devueltos por
la subrutina Perl. Los elementos reales devueltos por la subrutina se almacenan en el Perl
asociación.

Como regla general debe always verifique el valor de retorno de estas funciones. Incluso si
está esperando que solo se devuelva un número particular de valores de Perl
subrutina, no hay nada que impida que alguien haga algo inesperado, no digas
no ha sido advertido.

FLAG VALORES


El parámetro "banderas" en todos los llamar_* funciones es una de G_VOID, G_SCALAR o G_ARRAY,
que indican el contexto de la llamada, OR junto con una máscara de bits de cualquier combinación de
otros símbolos G_ * definidos a continuación.

G_VOID
Llama a la subrutina Perl en un contexto vacío.

Esta bandera tiene 2 efectos:

1. Indica a la subrutina que se está llamando que se está ejecutando en un contexto vacío.
(si ejecuta quieroarreglo el resultado será el valor indefinido).

2. Asegura que no se devuelva nada de la subrutina.

El valor devuelto por el llamar_* La función indica cuántos artículos han sido devueltos por
la subrutina Perl - en este caso será 0.

G_ESCALAR
Llama a la subrutina Perl en un contexto escalar. Esta es la configuración predeterminada del indicador de contexto.
para toda la llamar_* funciones.

Esta bandera tiene 2 efectos:

1. Indica a la subrutina que se está llamando que se está ejecutando en un contexto escalar.
(si ejecuta quieroarreglo el resultado será falso).

2. Asegura que solo se devuelva un escalar de la subrutina. El
La subrutina puede, por supuesto, ignorar la quieroarreglo y devuelva una lista de todos modos. Si es así,
entonces solo se devolverá el último elemento de la lista.

El valor devuelto por el llamar_* La función indica cuántos artículos han sido devueltos por
la subrutina Perl - en este caso será 0 o 1.

Si es 0, entonces ha especificado la bandera G_DISCARD.

Si es 1, entonces el elemento realmente devuelto por la subrutina Perl se almacenará en el Perl
pila - la sección Volviendo a Escalar muestra cómo acceder a este valor en la pila.
Recuerde que independientemente de cuántos elementos devuelva la subrutina Perl, solo el último
será accesible desde la pila; piense en el caso en el que solo se devuelve un valor como
siendo una lista con un solo elemento. Cualquier otro artículo que haya sido devuelto no existirá por
el control de tiempo regresa del llamar_* función. La sección Volviendo a lista in a
escalar contexto muestra un ejemplo de este comportamiento.

G_ARRAY
Llama a la subrutina Perl en un contexto de lista.

Al igual que con G_SCALAR, esta bandera tiene 2 efectos:

1. Indica a la subrutina que se está llamando que se está ejecutando en un contexto de lista.
(si ejecuta quieroarreglo el resultado será cierto).

2. Asegura que todos los elementos devueltos de la subrutina serán accesibles cuando
el control regresa del llamar_* función.

El valor devuelto por el llamar_* La función indica cuántos artículos han sido devueltos por
la subrutina Perl.

Si es 0, entonces ha especificado la bandera G_DISCARD.

Si no es 0, será un recuento del número de elementos devueltos por la subrutina. Estos
Los elementos se almacenarán en la pila de Perl. La sección Volviendo a lista of valores da un
ejemplo de uso de la bandera G_ARRAY y la mecánica de acceder a los elementos devueltos desde
la pila de Perl.

G_DESCARTAR
Por defecto, el llamar_* Las funciones colocan los elementos devueltos por la subrutina Perl en
la pila. Si no está interesado en estos elementos, establecer esta bandera hará
Perl se deshace de ellos automáticamente. Tenga en cuenta que todavía es posible indicar un
contexto a la subrutina Perl utilizando G_SCALAR o G_ARRAY.

Si no establece esta bandera, entonces es muy importante que se asegure de que cualquier
temporales (es decir, los parámetros pasados ​​a la subrutina Perl y los valores devueltos desde el
subrutina) se desechan usted mismo. La sección Volviendo a Escalar da detalles de cómo
deshacerse de estos provisionales explícitamente y la sección Gracias a Perl a disponer of
temporales analiza las circunstancias específicas en las que puede ignorar el problema y dejar que
Perl se encarga de ello por ti.

G_NOARGS
Siempre que se llame a una subrutina de Perl usando uno de los llamar_* funciones, es asumido por
por defecto, los parámetros se pasarán a la subrutina. Si no está pasando ninguna
parámetros a la subrutina Perl, puede ahorrar un poco de tiempo configurando este indicador. Eso
tiene el efecto de no crear la matriz @_ para la subrutina Perl.

Aunque la funcionalidad proporcionada por esta bandera puede parecer sencilla, debería ser
se usa solo si hay una buena razón para hacerlo. La razón para ser cauteloso es que, incluso
Si ha especificado el indicador G_NOARGS, todavía es posible que la subrutina Perl
ha sido llamado para pensar que le ha pasado parámetros.

De hecho, lo que puede suceder es que la subrutina Perl a la que ha llamado pueda acceder a @_
matriz de una subrutina Perl anterior. Esto ocurrirá cuando el código que se está ejecutando
los llamar_* La función en sí misma ha sido llamada desde otra subrutina de Perl. El código de abajo
ilustra esto

fred sub
{imprimir "@_ \ n"}

sub joe
{& fred}

& joe (1,2,3, XNUMX, XNUMX);

Esto imprimirá

1 2 3

Lo que ha sucedido es que "fred" accede a la matriz @_ que pertenece a "joe".

G_EVAL
Es posible que la subrutina Perl a la que está llamando termine de manera anormal, por ejemplo, por
llamar morir explícitamente o por no existir realmente. De forma predeterminada, cuando cualquiera de estos
eventos ocurran, el proceso terminará inmediatamente. Si quieres atrapar este tipo de
evento, especifique la bandera G_EVAL. Pondrá un eval { } alrededor de la llamada de subrutina.

Siempre que el control regrese del llamar_* función necesita verificar la variable $ @ mientras
lo haría en un script de Perl normal.

El valor devuelto por el llamar_* La función depende de qué otros indicadores se hayan
especificado y si se ha producido un error. Aquí están todos los diferentes casos que pueden
ocurrir:

· Si el llamar_* La función regresa normalmente, entonces el valor devuelto es el especificado en
las secciones anteriores.

· Si se especifica G_DISCARD, el valor devuelto siempre será 0.

· Si se especifica G_ARRAY y ha ocurrido un error, el valor de retorno siempre será 0.

· Si se especifica G_SCALAR y ha ocurrido un error, el valor de retorno será 1 y
el valor en la parte superior de la pila será undef. Esto significa que si ya lo ha hecho
detectó el error marcando $ @ y desea que el programa continúe, debe
recuerda hacer estallar el undef de la pila.

See Gracias a G_EVAL para obtener detalles sobre el uso de G_EVAL.

G_KEEPERR
El uso de la bandera G_EVAL descrita anteriormente siempre establecerá $ @: borrándolo si no hubo
error, y configurándolo para describir el error si hubo un error en el código llamado.
Esto es lo que desea si su intención es manejar posibles errores, pero a veces
solo quiero atrapar errores y evitar que interfieran con el resto del programa.

Este escenario se aplicará principalmente al código que debe llamarse desde dentro
destructores, devoluciones de llamada asincrónicas y manejadores de señales. En tales situaciones, donde el
El código que se llama tiene poca relación con el contexto dinámico circundante, el programa principal
necesita estar aislado de errores en el código llamado, incluso si no se pueden manejar
inteligentemente. También puede ser útil hacer esto con el código para "__DIE__" o "__WARN__"
ganchos y funciones de "atadura".

La bandera G_KEEPERR está destinada a utilizarse junto con G_EVAL en llamar_* funciones que
se utilizan para implementar dicho código, o con "eval_sv". Esta bandera no tiene ningún efecto en el
"call_ *" funciona cuando no se utiliza G_EVAL.

Cuando se usa G_KEEPERR, cualquier error en el código llamado terminará la llamada como de costumbre, y
el error no se propagará más allá de la llamada (como es habitual en G_EVAL), pero no irá
en $ @. En su lugar, el error se convertirá en una advertencia, con el prefijo de la cadena
"\ t (en limpieza)". Esto se puede deshabilitar usando "sin advertencias 'misc'". Si no hay error,
$ @ no se borrará.

Tenga en cuenta que la bandera G_KEEPERR no se propaga a evaluaciones internas; estos todavía pueden establecer $ @.

El indicador G_KEEPERR se introdujo en la versión 5.002 de Perl.

See Gracias a G_KEEPERR para un ejemplo de una situación que justifica el uso de esta bandera.

Determinando los Contexto
Como se mencionó anteriormente, puede determinar el contexto de la subrutina actualmente en ejecución en
Perl con quieroarreglo. La prueba equivalente se puede realizar en C utilizando la macro "GIMME_V",
que devuelve "G_ARRAY" si ha sido llamado en un contexto de lista, "G_SCALAR" si está en un
contexto escalar, o "G_VOID" si está en un contexto vacío (es decir, el valor de retorno no será
usado). Una versión anterior de esta macro se llama "GIMME"; en un contexto vacío vuelve
"G_SCALAR" en lugar de "G_VOID". Un ejemplo del uso de la macro "GIMME_V" se muestra en
. Gracias a DAME_V.

EJEMPLOS


¡Ya basta de hablar de definición! Veamos algunos ejemplos.

Perl proporciona muchas macros para ayudar a acceder a la pila de Perl. Siempre que sea posible, estos
Las macros siempre deben usarse al interactuar con los componentes internos de Perl. Esperamos que esto haga
el código es menos vulnerable a cualquier cambio realizado en Perl en el futuro.

Otro punto que vale la pena señalar es que en la primera serie de ejemplos solo he hecho uso de
los llamada_pv función. Esto se ha hecho para simplificar el código y facilitarle el acceso a la
tema. Siempre que sea posible, si la elección es entre usar llamada_pv y llamar_svusted debe
siempre trata de usar llamar_sv. Vea Gracias a llamar_sv para obtener más detalles.

No Parámetros Nada Devuelto
Este primer ejemplo trivial llamará a una subrutina de Perl, Imprimir UID, para imprimir el UID de
el proceso.

subImprimirUID
{
imprimir "UID es $ <\ n";
}

y aquí hay una función C para llamarlo

hoyo estatico
call_PrintUID ()
{
dSP;

PUSHMARK (SP);
call_pv ("PrintUID", G_DISCARD | G_NOARGS);
}

Simple, ¿eh?

Algunos puntos a tener en cuenta sobre este ejemplo:

1. Ignore "dSP" y "PUSHMARK (SP)" por ahora. Se analizarán en el siguiente ejemplo.

2. No pasamos ningún parámetro a Imprimir UID por lo que se puede especificar G_NOARGS.

3. No nos interesa nada devuelto de Imprimir UID, por lo que se especifica G_DISCARD.
Incluso si Imprimir UID se modificó para devolver algunos valores, habiendo especificado G_DISCARD
significa que serán borrados cuando el control de tiempo regrese de llamada_pv.

4. Como llamada_pv se está utilizando, la subrutina Perl se especifica como una cadena C. En esto
caso de que el nombre de la subrutina haya sido 'cableado' en el código.

5. Debido a que especificamos G_DISCARD, no es necesario verificar el valor devuelto por
llamada_pv. Siempre será 0.

Pasando (Paso) parámetros
Ahora hagamos un ejemplo un poco más complejo. Esta vez queremos llamar a Perl
subrutina, "LeftString", que tomará 2 parámetros: una cadena ($ s) y un número entero ($ n).
La subrutina simplemente imprimirá los primeros $ n caracteres de la cadena.

Entonces, la subrutina de Perl se vería así:

sub cadena izquierda
{
mi ($ s, $ n) = @_;
imprimir substr ($ s, 0, $ n), "\ n";
}

La función C requerida para llamar cadena izquierda se vería así:

hoyo estatico
call_LeftString (a, b)
carácter * a;
int b;
{
dSP;

INGRESAR;
GUARDARTMPS;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSVpv (a, 0)));
XPUSHs (sv_2mortal (newSViv (b)));
VOLVER;

call_pv ("LeftString", G_DISCARD);

TMPS LIBRES;
SALIR;
}

Aquí hay algunas notas sobre la función C call_LeftString.

1. Los parámetros se pasan a la subrutina Perl usando la pila Perl. Este es el
propósito del código que comienza con la línea "dSP" y termina con la línea "PUTBACK".
El "dSP" declara una copia local del puntero de pila. Esta copia local debe always
ser accedido como "SP".

2. Si va a poner algo en la pila de Perl, necesita saber dónde poner
eso. Este es el propósito de la macro "dSP": declara e inicializa un local copia
del puntero de pila de Perl.

Todas las demás macros que se utilizarán en este ejemplo requieren que haya utilizado este
macro.

La excepción a esta regla es si está llamando a una subrutina Perl directamente desde un
Función XSUB. En este caso, no es necesario utilizar la macro "dSP" explícitamente, ya que
será declarado para usted automáticamente.

3. Todos los parámetros que se van a insertar en la pila deben estar entre corchetes con "PUSHMARK" y
Macros "PUTBACK". El propósito de estas dos macros, en este contexto, es contar la
número de parámetros que está presionando automáticamente. Entonces, siempre que Perl esté creando
la matriz @_ para la subrutina, sabe qué tan grande hacerla.

La macro "PUSHMARK" le dice a Perl que tome nota mental del puntero de pila actual.
Incluso si no está pasando ningún parámetro (como el ejemplo que se muestra en la sección No
Parámetros Nada Devuelto) aún debe llamar a la macro "PUSHMARK" antes de poder
llamar a cualquiera de los llamar_* funciones - Perl todavía necesita saber que no hay
parámetros.

La macro "PUTBACK" establece la copia global del puntero de la pila para que sea la misma que nuestra
copia local. Si no hicimos esto, llamada_pv no sabría dónde están los dos parámetros que
empujados fueron: recuerde que hasta ahora toda la manipulación del puntero de la pila que hemos hecho
está con nuestra copia local, no la copia global.

4. A continuación, llegamos a XPUSHs. Aquí es donde los parámetros realmente se insertan en el
apilar. En este caso, estamos presionando una cadena y un número entero.

Consulte "XSUB y la pila de argumentos" en perlguts para obtener detalles sobre cómo las macros XPUSH
extra.

5. Porque creamos valores temporales (mediante sv_2mortal () llamadas) tendremos que
Ordene la pila de Perl y elimine los SV mortales.

Este es el propsito de

INGRESAR;
GUARDARTMPS;

al inicio de la función, y

TMPS LIBRES;
SALIR;

al final. El par "ENTER" / "SAVETMPS" crea un límite para cualquier temporal que
crear. Esto significa que los temporales de los que nos deshagamos se limitarán a aquellos que
fueron creados después de estas llamadas.

El par "FREETMPS" / "LEAVE" eliminará cualquier valor devuelto por Perl
subrutina (vea el siguiente ejemplo), además de que también volcará los SV mortales que hemos creado.
Tener "ENTER" / "SAVETMPS" al principio del código asegura que ningún otro
los mortales son destruidos.

Piense que estas macros funcionan un poco como "{" y "}" en Perl para limitar el alcance de
variables locales.

Ver la sección Gracias a Perl a tiene of Temporarios para obtener detalles de una alternativa a
utilizando estas macros.

6. Finalmente, cadena izquierda ahora se puede llamar a través del llamada_pv función. La única bandera
especificado este tiempo es G_DISCARD. Porque estamos pasando 2 parámetros al Perl
subrutina esta vez, no hemos especificado G_NOARGS.

Volviendo a Escalar
Veamos ahora un ejemplo de cómo tratar los elementos devueltos desde una subrutina de Perl.

Aquí hay una subrutina de Perl, Adder, que toma 2 parámetros enteros y simplemente devuelve su
suma.

Sumador secundario
{
mi ($ a, $ b) = @_;
$ a + $ b;
}

Porque ahora nos preocupa el valor de retorno de Adder, la función C requerida para
llamarlo ahora es un poco más complejo.

hoyo estatico
call_Adder (a, b)
int a;
int b;
{
dSP;
int cuenta;

INGRESAR;
GUARDARTMPS;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSViv (a)));
XPUSHs (sv_2mortal (newSViv (b)));
VOLVER;

count = call_pv ("Sumador", G_SCALAR);

ESPAÑA;

si (cuenta! = 1)
croar ("Gran problema \ n");

printf ("La suma de% d y% d es% d \ n", a, b, POPi);

VOLVER;
TMPS LIBRES;
SALIR;
}

Los puntos a tener en cuenta esta vez son

1. La única bandera especificada esta vez fue G_SCALAR. Eso significa que la matriz @_ será
creado y que el valor devuelto por Adder seguirá existiendo después de la llamada a
llamada_pv.

2. El propósito de la macro "SPAGAIN" es actualizar la copia local del puntero de pila.
Esto es necesario porque es posible que la memoria asignada a la pila de Perl
ha sido reasignado durante el llamada_pv llamada.

Si está utilizando el puntero de pila de Perl en su código, siempre debe actualizar
la copia local utilizando SPAGAIN siempre que haga uso del llamar_* funciones o cualquier
otra función interna de Perl.

3. Aunque se esperaba que solo se devolviera un valor de Adder, sigue siendo bueno
práctica para comprobar el código de retorno de llamada_pv de todos modos.

Esperar un valor único no es lo mismo que saber que habrá uno. Si
alguien modificado Adder para devolver una lista y no verificamos esa posibilidad y
Tome las medidas adecuadas, la pila de Perl terminaría en un estado inconsistente. Es decir
algo tu realmente no quiero que suceda nunca.

4. La macro "POPi" se utiliza aquí para extraer el valor de retorno de la pila. En este caso
queríamos un número entero, por lo que se usó "POPi".

Aquí está la lista completa de macros POP disponibles, junto con los tipos que devuelven.

COPs SV
Puntero POPp
POPn doble
Entero POPi
POPl de largo

5. El "PUTBACK" final se usa para dejar la pila de Perl en un estado consistente antes
salir de la función. Esto es necesario porque cuando sacamos el valor de retorno de
la pila con "POPi" actualizó solo nuestra copia local del puntero de la pila. Recordar,
"PUTBACK" establece el puntero de la pila global para que sea el mismo que nuestra copia local.

Volviendo a Lista of Valores
Ahora, ampliemos el ejemplo anterior para devolver tanto la suma de los parámetros como la
diferencia.

Aquí está la subrutina de Perl

sub Suma Resta
{
mi ($ a, $ b) = @_;
($ a + $ b, $ a- $ b);
}

y esta es la función C

hoyo estatico
call_AddSubtract (a, b)
int a;
int b;
{
dSP;
int cuenta;

INGRESAR;
GUARDARTMPS;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSViv (a)));
XPUSHs (sv_2mortal (newSViv (b)));
VOLVER;

count = call_pv ("Sumar restar", G_ARRAY);

ESPAÑA;

si (cuenta! = 2)
croar ("Gran problema \ n");

printf ("% d -% d =% d \ n", a, b, POPi);
printf ("% d +% d =% d \ n", a, b, POPi);

VOLVER;
TMPS LIBRES;
SALIR;
}

If call_AddSubtract se llama así

call_AddSubtract (7, 4);

entonces aquí está la salida

7 - 4 3 =
7 + = 4 11

Notas

1. Queríamos un contexto de lista, por lo que se utilizó G_ARRAY.

2. No es sorprendente que "POPi" se use dos veces esta vez porque estábamos recuperando 2 valores
de la pila. Lo importante a tener en cuenta es que cuando se utilizan las macros "POP *"
salir de la pila en marcha atrás orden.

Volviendo a Lista in a Escalar Contexto
Digamos que la subrutina Perl de la sección anterior se llamó en un contexto escalar, como este

hoyo estatico
call_AddSubScalar (a, b)
int a;
int b;
{
dSP;
int cuenta;
int i;

INGRESAR;
GUARDARTMPS;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSViv (a)));
XPUSHs (sv_2mortal (newSViv (b)));
VOLVER;

count = call_pv ("Sumar restar", G_SCALAR);

ESPAÑA;

printf ("Artículos devueltos =% d \ n", recuento);

para (i = 1; i <= contar; ++ i)
printf ("Valor% d =% d \ n", i, POPi);

VOLVER;
TMPS LIBRES;
SALIR;
}

La otra modificación realizada es que call_AddSubScalar imprimirá el número de artículos
devuelto de la subrutina Perl y su valor (por simplicidad se supone que son
entero). Así que si call_AddSubScalar se llama

call_AddSubScalar (7, 4);

entonces la salida será

Artículos devueltos = 1
Valor 1 = 3

En este caso, el punto principal a tener en cuenta es que solo se devuelve el último elemento de la lista
de la subrutina. Sumar Restar en realidad regresó a call_AddSubScalar.

Volviendo Data obtenidos de Perl vía los Parámetro Lista
También es posible devolver valores directamente a través de la lista de parámetros, ya sea
realmente deseable hacerlo es otro asunto completamente diferente.

La subrutina Perl, Inc, a continuación, toma 2 parámetros e incrementa cada uno directamente.

sub inc.
{
++ $ _ [0];
++ $ _ [1];
}

y aquí hay una función en C para llamarlo.

hoyo estatico
call_Inc (a, b)
int a;
int b;
{
dSP;
int cuenta;
SV*sva;
SV * svb;

INGRESAR;
GUARDARTMPS;

sva = sv_2mortal (newSViv (a));
svb = sv_2mortal (newSViv (b));

PUSHMARK (SP);
XPUSHs (sva);
XPUSHs (svb);
VOLVER;

count = call_pv ("Inc", G_DISCARD);

si (cuenta! = 0)
croak ("call_Inc: valores 0 esperados de 'Inc', obtuvo% d \ n",
contar);

printf ("% d + 1 =% d \ n", a, SvIV (sva));
printf ("% d + 1 =% d \ n", b, SvIV (svb));

TMPS LIBRES;
SALIR;
}

Para poder acceder a los dos parámetros que se enviaron a la pila después de su regreso
obtenidos de llamada_pv es necesario tomar nota de sus direcciones, por lo que las dos variables
"sva" y "svb".

La razón por la que esto es necesario es que el área de la pila de Perl que los contenía será muy
Probablemente haya sido sobrescrito por otra cosa por el tiempo que el control regresa de llamada_pv.

Gracias a G_EVAL
Ahora un ejemplo usando G_EVAL. A continuación se muestra una subrutina de Perl que calcula la diferencia de
sus 2 parámetros. Si esto daría como resultado un resultado negativo, la subrutina llama morir.

restar restar
{
mi ($ a, $ b) = @_;

morir "la muerte puede ser fatal \ n" si $ a <$ b;

$ a - $ b;
}

y algo de C para llamarlo

hoyo estatico
restar_llamada (a, b)
int a;
int b;
{
dSP;
int cuenta;

INGRESAR;
GUARDARTMPS;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSViv (a)));
XPUSHs (sv_2mortal (newSViv (b)));
VOLVER;

count = call_pv ("Restar", G_EVAL | G_SCALAR);

ESPAÑA;

/ * Verifique la evaluación primero * /
si (SvTRUE (ERRSV))
{
printf ("Uh oh -% s \ n", SvPV_nolen (ERRSV));
COP;
}
más
{
si (cuenta! = 1)
croak ("call_Subtract: quería 1 valor de 'Restar', obtuve% d \ n",
contar);

printf ("% d -% d =% d \ n", a, b, POPi);
}

VOLVER;
TMPS LIBRES;
SALIR;
}

If llamada_restar se llama así

restar_llamada (4, 5)

se imprimirá lo siguiente

Uh oh - la muerte puede ser fatal

Notas

1. Queremos poder captar la morir por lo que hemos utilizado la bandera G_EVAL. Sin especificar
esta bandera significaría que el programa terminaría inmediatamente en el morir
declaración en la subrutina Sustraer.

2. El código

si (SvTRUE (ERRSV))
{
printf ("Uh oh -% s \ n", SvPV_nolen (ERRSV));
COP;
}

es el equivalente directo de este bit de Perl

imprimir "Uh oh - $ @ \ n" si $ @;

"PL_errgv" es un perl global de tipo "GV *" que apunta a la entrada de la tabla de símbolos
que contiene el error. Por lo tanto, "ERRSV" se refiere al equivalente en C de $ @.

3. Tenga en cuenta que la pila se abre utilizando "POP" en el bloque donde "SvTRUE (ERRSV)" es
verdadero. Esto es necesario porque siempre que un llamar_* función invocada con
G_EVAL | G_SCALAR devuelve un error, la parte superior de la pila contiene el valor undef. Porque
queremos que el programa continúe después de detectar este error, es fundamental que el
La pila se ordenará quitando el undef.

Gracias a G_KEEPERR
Considere este ejemplo bastante gracioso, donde hemos usado una versión XS del
Ejemplo de call_Subtract arriba dentro de un destructor:

paquete Foo;
sub nuevo {bendiga {}, $ _ [0]}
restar Restar {
mi ($ a, $ b) = @_;
morir "la muerte puede ser fatal" si $ a <$ b;
$ a - $ b;
}
sub DESTROY {call_Subtract (5, 4); }
sub foo {die "foo dies"; }

paquete principal;
{
my $ foo = Foo-> nuevo;
eval {$ foo-> foo};
}
imprimir "Sierra: $ @" si $ @; # debería ser, pero no lo es

Este ejemplo no reconocerá que ocurrió un error dentro de "eval {}". Aquí está
por qué: el código call_Subtract se ejecutó mientras Perl limpiaba los temporales cuando
salir del bloque exterior arriostrado, y porque call_Subtract se implementa con llamada_pv
usando la bandera G_EVAL, rápidamente restableció $ @. Esto da como resultado el fracaso del más externo
prueba para $ @ y, por lo tanto, la falla de la trampa de error.

Agregar el indicador G_KEEPERR, de modo que el llamada_pv llamar en call_Subtract lee:

count = call_pv ("Restar", G_EVAL | G_SCALAR | G_KEEPERR);

preservará el error y restaurará un manejo confiable de errores.

Gracias a llamar_sv
En todos los ejemplos anteriores he 'cableado' el nombre de la subrutina Perl para ser
llamado desde C.La mayoría de las veces, sin embargo, es más conveniente poder especificar el
nombre de la subrutina Perl desde dentro del script Perl.

Considere el código Perl a continuación

fred sub
{
imprimir "Hola \ n";
}

CallSubPV ("fred");

Aquí hay un fragmento de XSUB que define LlamarSubPV.

vacío
CallSubPV (nombre)
nombre del personaje
CÓDIGO:
PUSHMARK (SP);
call_pv (nombre, G_DISCARD | G_NOARGS);

Eso está bien hasta donde llega. El caso es que la subrutina Perl se puede especificar como
una cadena, sin embargo, Perl permite referencias a subrutinas y subrutinas anónimas. Esta
es donde llamar_sv es útil.

El siguiente código para LlamarSubSV es idéntico a LlamarSubPV excepto que el parámetro "nombre" es
ahora definido como un SV * y usamos llamar_sv en lugar de llamada_pv.

vacío
CallSubSV (nombre)
SV * nombre
CÓDIGO:
PUSHMARK (SP);
call_sv (nombre, G_DISCARD | G_NOARGS);

Porque estamos usando un SV para llamar Fred se pueden usar todos los siguientes:

CallSubSV ("fred");
CallSubSV (\ & fred);
$ ref = \ & fred;
CallSubSV ($ ref);
CallSubSV (sub {print "Hola \ n"});

Como se puede ver, llamar_sv le da mucha mayor flexibilidad en cómo puede especificar el Perl
subrutina.

Debe tener en cuenta que, si es necesario almacenar el SV ("nombre" en el ejemplo anterior)
que corresponde a la subrutina Perl para que pueda usarse más tarde en el programa,
no basta con almacenar una copia del puntero al SV. Digamos que el código anterior había sido como
modo:

SV estático * recordarSub;

vacío
SaveSub1 (nombre)
SV * nombre
CÓDIGO:
recordarSub = nombre;

vacío
CallSavedSub1 ()
CÓDIGO:
PUSHMARK (SP);
call_sv (recordarSub, G_DISCARD | G_NOARGS);

La razón por la que esto es incorrecto es que, cuando empiece a usar el puntero "recordarSub" en
"CallSavedSub1", puede o no hacer referencia a la subrutina Perl que se registró en
"SaveSub1". Esto es particularmente cierto para estos casos:

SaveSub1 (\ & fred);
CallSavedSub1 ();

SaveSub1 (sub {print "Hola \ n"});
CallSavedSub1 ();

En el momento en que se haya ejecutado cada una de las declaraciones "SaveSub1" anteriores, los SV * s que
correspondiente a los parámetros ya no existirá. Espere un mensaje de error de Perl de
la forma

No se puede usar un valor indefinido como referencia de subrutina en ...

para cada una de las líneas "CallSavedSub1".

Del mismo modo, con este código

$ ref = \ & fred;
SaveSub1 ($ ref);
$ ref = 47;
CallSavedSub1 ();

puede esperar uno de estos mensajes (que en realidad recibe depende de la versión
de Perl que estás usando)

No es una referencia de CÓDIGO en ...
Subrutina indefinida & main :: 47 llamado ...

La variable $ ref puede haberse referido a la subrutina "fred" siempre que la llamada a
Se creó "SaveSub1", pero cuando se llama "CallSavedSub1", ahora tiene el número
47. Como solo guardamos un puntero al SV original en "SaveSub1", cualquier cambio en $ ref
será rastreado por el puntero "RememberSub". Esto significa que siempre que "CallSavedSub1"
se llama, intentará ejecutar el código al que hace referencia el SV *
"recuerdaSub". En este caso, sin embargo, ahora se refiere al entero 47, así que espere que Perl
quejarse en voz alta.

Un problema similar pero más sutil se ilustra con este código:

$ ref = \ & fred;
SaveSub1 ($ ref);
$ ref = \ & joe;
CallSavedSub1 ();

Esta vez, siempre que se llame a "CallSavedSub1", se ejecutará la subrutina de Perl "joe".
(asumiendo que existe) en lugar de "fred" como se solicitó originalmente en la llamada a
"SaveSub1".

Para solucionar estos problemas es necesario realizar una copia completa del SV. El código
a continuación se muestra "SaveSub2" modificado para hacer eso.

SV estático * keepSub = (SV *) NULL;

vacío
SaveSub2 (nombre)
SV * nombre
CÓDIGO:
/ * Tomar una copia de la devolución de llamada * /
si (keepSub == (SV *) NULL)
/ * Primera vez, así que crea un nuevo SV * /
keepSub = newSVsv (nombre);
más
/ * He estado aquí antes, así que sobrescribe * /
SvSetSV (keepSub, nombre);

vacío
CallSavedSub2 ()
CÓDIGO:
PUSHMARK (SP);
call_sv (keepSub, G_DISCARD | G_NOARGS);

Para evitar crear un nuevo SV cada vez que se llama a "SaveSub2", la función primero verifica
ver si se ha llamado antes. De lo contrario, se asigna espacio para un nuevo SV y el
la referencia a la subrutina de Perl "nombre" se copia a la variable "keepSub" en una
operación usando "newSVsv". A partir de entonces, siempre que se llame a "SaveSub2", el SV existente,
"keepSub", se sobrescribe con el nuevo valor usando "SvSetSV".

Gracias a llamada_argv
Aquí hay una subrutina de Perl que imprime los parámetros que se le pasan.

sub lista de impresión
{
mi (@lista) = @_;

foreach (@list) {imprimir "$ _ \ n"}
}

Y aquí hay un ejemplo de llamada_argv que llamará Imprimir lista.

carácter estático * palabras [] = {"alfa", "beta", "gamma", "delta", NULL};

hoyo estatico
call_PrintList ()
{
dSP;

call_argv ("Lista de impresión", G_DISCARD, palabras);
}

Tenga en cuenta que no es necesario llamar a "PUSHMARK" en este caso. Esto es porque
llamada_argv lo hará por ti.

Gracias a método_de_llamada
Considere el siguiente código Perl:

{
paquete Mine;

sub nuevo
{
mi ($ tipo) = turno;
bendecir [@_]
}

pantalla secundaria
{
my ($ yo, $ índice) = @_;
imprimir "$ índice: $$ self [$ índice] \ n";
}

sub ID de impresión
{
mi ($ clase) = @_;
print "Esta es la clase Class $ versión 1.0 \ n";
}
}

Implementa solo una clase muy simple para administrar una matriz. Aparte del constructor,
"nuevo", declara métodos, uno estático y otro virtual. El método estático, "PrintID",
imprime simplemente el nombre de la clase y un número de versión. El método virtual, "Display",
imprime un solo elemento de la matriz. Aquí hay un ejemplo de uso de Perl.

$ a = Mine-> new ('rojo', 'verde', 'azul');
$ a->Pantalla(1);
Mine-> PrintID;

imprimirá

1: verde
Esta es la versión 1.0 de Class Mine

Llamar a un método Perl desde C es bastante sencillo. Se requieren las siguientes cosas:

· Una referencia al objeto para un método virtual o el nombre de la clase para un estático.
Método

· El nombre del método

· Cualquier otro parámetro específico del método

Aquí hay un XSUB simple que ilustra la mecánica de llamar a "PrintID" y
Métodos de "visualización" de C.

vacío
call_Method (ref, método, índice)
SV * referencia
método char *
int índice
CÓDIGO:
PUSHMARK (SP);
XPUSHs (ref);
XPUSHs (sv_2mortal (newSViv (índice)));
VOLVER;

call_method (método, G_DISCARD);

vacío
call_PrintID (clase, método)
char * clase
método char *
CÓDIGO:
PUSHMARK (SP);
XPUSHs (sv_2mortal (newSVpv (clase, 0)));
VOLVER;

call_method (método, G_DISCARD);

Entonces, los métodos "PrintID" y "Display" se pueden invocar así:

$ a = Mine-> new ('rojo', 'verde', 'azul');
call_Method ($ a, 'Pantalla', 1);
call_PrintID ('Mine', 'PrintID');

Lo único a tener en cuenta es que, tanto en el método estático como en el virtual, el nombre del método es
no se pasa a través de la pila: se usa como el primer parámetro para método_de_llamada.

Gracias a DAME_V
Aquí hay un XSUB trivial que imprime el contexto en el que se está ejecutando actualmente.

vacío
PrintContext ()
CÓDIGO:
I32 dame = GIMME_V;
si (dame == G_VOID)
printf ("El contexto es nulo \ n");
más si (dame == G_SCALAR)
printf ("El contexto es escalar \ n");
más
printf ("El contexto es una matriz \ n");

Y aquí hay algo de Perl para probarlo.

ImprimirContexto;
$ a = PrintContext;
@a = ImprimirContexto;

La salida de eso será

El contexto es nulo
El contexto es escalar
El contexto es una matriz

Gracias a Perl a tiene of Temporarios
En los ejemplos dados hasta la fecha, cualquier temporal creado en la devolución de llamada (es decir, parámetros
pasado en la pila a la llamar_* función o valores devueltos a través de la pila) han sido
liberado por uno de estos métodos:

· Especificando la bandera G_DISCARD con llamar_*

· Uso explícito del emparejamiento "ENTER" / "SAVETMPS" - "FREETMPS" / "LEAVE"

Hay otro método que se puede utilizar, a saber, dejar que Perl lo haga por usted automáticamente.
siempre que recupere el control después de que finalice la devolución de llamada. Esto se hace simplemente no
usando el

INGRESAR;
GUARDARTMPS;
...
TMPS LIBRES;
SALIR;

secuencia en la devolución de llamada (y no, por supuesto, especificando el indicador G_DISCARD).

Si va a utilizar este método, debe tener en cuenta una posible pérdida de memoria que
puede surgir en circunstancias muy específicas. Para explicar estas circunstancias es necesario
saber un poco sobre el flujo de control entre Perl y la rutina de devolución de llamada.

Los ejemplos dados al comienzo del documento (un controlador de errores y un evento controlado
programa) son típicos de los dos tipos principales de control de flujo que probablemente
encuentro con devoluciones de llamada. Hay una distinción muy importante entre ellos, así que paga
atención.

En el primer ejemplo, un controlador de errores, el flujo de control podría ser el siguiente. Tienes
creó una interfaz para una biblioteca externa. El control puede llegar a la biblioteca externa como
este vídeo

perl -> XSUB -> biblioteca externa

Mientras el control está en la biblioteca, se produce una condición de error. Ha configurado previamente un
Devolución de llamada de Perl para manejar esta situación, por lo que se ejecutará. Una vez que la devolución de llamada
terminado, el control volverá a Perl. Esto es lo que será el flujo de control.
como en esa situacion

perl -> XSUB -> biblioteca externa
...
se produce un error
...
biblioteca externa -> call_ * -> perl
|
perl <- XSUB <- biblioteca externa <- call_ * <---- +

Después de procesar el error usando llamar_* se completa, el control vuelve a Perl más
o menos inmediatamente.

En el diagrama, cuanto más a la derecha vaya, más profundamente anidado estará el osciloscopio. Es solo
cuando el control vuelva con perl en el extremo izquierdo del diagrama, tendrá
se dejó caer de nuevo al alcance adjunto y los provisionales que haya dejado colgando se
Se liberado.

En el segundo ejemplo, un programa impulsado por eventos, el flujo de control será más parecido a este

perl -> XSUB -> controlador de eventos
...
controlador de eventos -> call_ * -> perl
|
controlador de eventos <- call_ * <---- +
...
controlador de eventos -> call_ * -> perl
|
controlador de eventos <- call_ * <---- +
...
controlador de eventos -> call_ * -> perl
|
controlador de eventos <- call_ * <---- +

En este caso, el flujo de control puede consistir solo en la secuencia repetida

controlador de eventos -> call_ * -> perl

durante prácticamente toda la duración del programa. Esto significa que el control puede nunca
volver al visor circundante en Perl en el extremo izquierdo.

Entonces, ¿cuál es el gran problema? Bueno, si espera que Perl arregle esos temporales
para usted, es posible que tenga una larga espera. Para que Perl se deshaga de sus provisionales,
el control debe volver al alcance adjunto en algún momento. En el escenario impulsado por eventos
eso puede que nunca suceda. Esto significa que, a medida que pasa el tiempo, su programa creará más
y más temporales, ninguno de los cuales será liberado jamás. Como cada uno de estos temporales
consume algo de memoria su programa eventualmente consumirá toda la memoria disponible en su
sistema - kapow!

Así que aquí está la conclusión: si está seguro de que el control volverá a la
Perl alcance bastante rápido después del final de su devolución de llamada, entonces no es absolutamente
necesario deshacerse explícitamente de los temporales que haya creado. Eso sí, si tu
no está seguro de qué hacer, de todos modos no hace ningún daño ordenar.

Estrategias for Almacenamiento Devolución de llamada Contexto Información
Potencialmente uno de los problemas más difíciles de superar al diseñar una interfaz de devolución de llamada
puede estar averiguando cómo almacenar el mapeo entre la función de devolución de llamada de C y el Perl
equivalente.

Para ayudar a comprender por qué esto puede ser un problema real, primero considere cómo se configura una devolución de llamada
en un entorno todo C. Normalmente, una API C proporcionará una función para registrar un
llamar de vuelta. Esto esperará un puntero a una función como uno de sus parámetros. A continuación se muestra un
llamada a una función hipotética "register_fatal" que registra la función C para obtener
llamado cuando ocurre un error fatal.

register_fatal (cb1);

El único parámetro "cb1" es un puntero a una función, por lo que debe haber definido "cb1" en
tu código, di algo como esto

hoyo estatico
cb1 ()
{
printf ("Error fatal \ n");
salida(1);
}

Ahora cambie eso para llamar a una subrutina Perl en su lugar

devolución de llamada SV * estática = (SV *) NULL;

hoyo estatico
cb1 ()
{
dSP;

PUSHMARK (SP);

/ * Llame al sub de Perl para procesar la devolución de llamada * /
call_sv (devolución de llamada, G_DISCARD);
}

vacío
register_fatal (fn)
SV * fn
CÓDIGO:
/ * Recuerda el sub de Perl * /
if (devolución de llamada == (SV *) NULL)
devolución de llamada = newSVsv (fn);
más
SvSetSV (devolución de llamada, fn);

/ * registrar la devolución de llamada con la biblioteca externa * /
register_fatal (cb1);

donde el equivalente en Perl de "register_fatal" y la devolución de llamada que registra, "pcb1", podrían
se parece a esto

# Registre el sub pcb1
register_fatal (\ & pcb1);

subpcb1
{
morir "Me estoy muriendo ... \ n";
}

El mapeo entre la devolución de llamada de C y el equivalente de Perl se almacena en el
variable "devolución de llamada".

Esto será adecuado si alguna vez necesita tener una sola devolución de llamada registrada en cualquier momento.
Un ejemplo podría ser un controlador de errores como el código esbozado anteriormente. Aunque recuerda,
las llamadas repetidas a "register_fatal" reemplazarán la devolución de llamada registrada anteriormente
Funcionar con el nuevo.

Digamos, por ejemplo, que desea conectarse a una biblioteca que permita la E / S de archivos asíncrona. En
En este caso, es posible que pueda registrar una devolución de llamada siempre que se haya completado una operación de lectura.
Para ser de alguna utilidad, queremos poder llamar subrutinas Perl separadas para cada archivo que
está abierto. Tal como está, el ejemplo del controlador de errores anterior no sería adecuado ya que
permite que solo se defina una única devolución de llamada en cualquier momento. Lo que necesitamos es un medio de
almacenar el mapeo entre el archivo abierto y la subrutina Perl que queremos que se llame
para ese archivo.

Digamos que la biblioteca de E / S tiene una función "asynch_read" que asocia una función C
"ProcessRead" con un identificador de archivo "fh" - esto supone que también ha proporcionado alguna rutina
para abrir el archivo y así obtener el identificador del archivo.

asynch_read (fh, ProcessRead)

Esto puede esperar la C Proceso de lectura función de esta forma

vacío
ProcessRead (fh, búfer)
intfh;
char * búfer;
{
...
}

Para proporcionar una interfaz de Perl a esta biblioteca, necesitamos poder mapear entre el "fh"
y la subrutina Perl que queremos llamar. Un hash es un mecanismo conveniente para
almacenar este mapeo. El siguiente código muestra una posible implementación

Mapeo estático HV * = (HV *) NULL;

vacío
asynch_read (fh, devolución de llamada)
intfh
SV * devolución de llamada
CÓDIGO:
/ * Si el hash aún no existe, créelo * /
if (Mapeo == (HV *) NULL)
Mapeo = newHV ();

/ * Guarde el fh -> mapeo de devolución de llamada * /
hv_store (Mapeo, (char *) & fh, sizeof (fh), newSVsv (devolución de llamada), 0);

/ * Registrarse en la biblioteca C * /
asynch_read (fh, asynch_read_if);

y "asynch_read_if" podría verse así

hoyo estatico
asynch_read_if (fh, búfer)
intfh;
char * búfer;
{
dSP;
SV**sv;

/ * Obtiene la devolución de llamada asociada con fh * /
sv = hv_fetch (Mapeo, (char *) & fh, tamaño de (fh), FALSE);
si (sv == (SV **) NULL)
croak ("Error interno ... \ n");

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSViv (fh)));
XPUSHs (sv_2mortal (newSVpv (búfer, 0)));
VOLVER;

/ * Llamar al sub de Perl * /
call_sv (* sv, G_DISCARD);
}

Para completar, aquí está "asynch_close". Esto muestra cómo eliminar la entrada del
hash "Mapeo".

vacío
asynch_close (fh)
intfh
CÓDIGO:
/ * Eliminar la entrada del hash * /
(void) hv_delete (Mapeo, (char *) & fh, tamaño de (fh), G_DISCARD);

/ * Ahora llama al asynch_close real * /
asynch_close (fh);

Entonces la interfaz de Perl se vería así

devolución de llamada secundaria1
{
mi ($ mango, $ búfer) = @_;
}

# Registre la devolución de llamada de Perl
asynch_read ($ fh, \ & devolución de llamada1);

asynch_close ($ fh);

El mapeo entre la devolución de llamada de C y Perl se almacena en el hash global "Mapping" this
hora. El uso de un hash tiene la clara ventaja de que permite un número ilimitado de
devoluciones de llamada para ser registrados.

¿Qué pasa si la interfaz proporcionada por la devolución de llamada C no contiene un parámetro que permita
el identificador de archivo para el mapeo de subrutinas de Perl? Digamos que en el paquete de E / S asincrónico, el
la función de devolución de llamada se pasa solo el parámetro "búfer" como este

vacío
ProcessRead (búfer)
char * búfer;
{
...
}

Sin el identificador de archivo, no hay una forma sencilla de mapear desde la devolución de llamada C a la
Subrutina Perl.

En este caso, una posible forma de solucionar este problema es predefinir una serie de funciones C para
actuar como la interfaz de Perl, por lo que

#definir MAX_CB 3
#definir NULL_HANDLE -1
typedef void (* FnMap) ();

estructura MapStruct {
Función FnMap;
SV * PerlSub;
Manija interna;
};

vacío estático fn1 ();
vacío estático fn2 ();
vacío estático fn3 ();

Estructura estática MapStruct Map [MAX_CB] =
{
{fn1, NULL, NULL_HANDLE},
{fn2, NULL, NULL_HANDLE},
{fn3, NULL, NULL_HANDLE}
};

hoyo estatico
Pcb (índice, búfer)
índice int;
char * búfer;
{
dSP;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSVpv (búfer, 0)));
VOLVER;

/ * Llamar al sub de Perl * /
call_sv (Mapa [índice] .PerlSub, G_DISCARD);
}

hoyo estatico
fn1 (búfer)
char * búfer;
{
Pcb (0, búfer);
}

hoyo estatico
fn2 (búfer)
char * búfer;
{
Pcb (1, búfer);
}

hoyo estatico
fn3 (búfer)
char * búfer;
{
Pcb (2, búfer);
}

vacío
array_asynch_read (fh, devolución de llamada)
intfh
SV * devolución de llamada
CÓDIGO:
índice int;
int índice_nulo = MAX_CB;

/ * Encuentra el mismo identificador o una entrada vacía * /
para (índice = 0; índice <MAX_CB; ++ índice)
{
if (Mapa [índice] .Handle == fh)
break;

if (Mapa [índice] .Handle == NULL_HANDLE)
índice_nulo = índice;
}

si (índice == MAX_CB && null_index == MAX_CB)
croak ("Demasiadas funciones de devolución de llamada registradas \ n");

si (índice == MAX_CB)
índice = null_index;

/ * Guarde el identificador del archivo * /
Mapa [índice] .Handle = fh;

/ * Recuerda el sub de Perl * /
if (Mapa [índice] .PerlSub == (SV *) NULL)
Mapa [índice] .PerlSub = newSVsv (devolución de llamada);
más
SvSetSV (Mapa [índice] .PerlSub, devolución de llamada);

asynch_read (fh, Map [índice] .Función);

vacío
array_asynch_close (fh)
intfh
CÓDIGO:
índice int;

/ * Encuentra el identificador del archivo * /
para (índice = 0; índice <MAX_CB; ++ índice)
if (Mapa [índice] .Handle == fh)
break;

si (índice == MAX_CB)
croak ("no se pudo cerrar fh% d \ n", fh);

Map [index] .Handle = NULL_HANDLE;
SvREFCNT_dec (Mapa [índice] .PerlSub);
Mapa [índice] .PerlSub = (SV *) NULL;

asynch_close (fh);

En este caso, las funciones "fn1", "fn2" y "fn3" se utilizan para recordar el Perl
subrutina a llamar. Cada una de las funciones tiene un índice cableado independiente que es
usado en la función "Pcb" para acceder a la matriz "Map" y realmente llamar al Perl
subrutina.

Hay algunas desventajas obvias con esta técnica.

En primer lugar, el código es considerablemente más complejo que en el ejemplo anterior.

En segundo lugar, existe un límite fijo (en este caso 3) para la cantidad de devoluciones de llamada que pueden
existen simultáneamente. La única forma de aumentar el límite es modificando el código para agregar
más funciones y luego recompilar. No obstante, siempre que el número de funciones sea
elegido con cierto cuidado, sigue siendo una solución viable y, en algunos casos, es la única
para todos.

Para resumir, aquí hay varios métodos posibles que debe considerar para almacenar el
mapeo entre C y la devolución de llamada de Perl

1. Ignore el problema: permita solo 1 devolución de llamada
Para muchas situaciones, como interactuar con un controlador de errores, esto puede ser una
solución perfectamente adecuada.

2. Cree una secuencia de devoluciones de llamada: límite cableado
Si es imposible saber a partir de los parámetros devueltos desde la devolución de llamada C, qué
el contexto es, entonces es posible que deba crear una secuencia de interfaz de devolución de llamada C
funciones y almacenar punteros a cada uno en una matriz.

3. Utilice un parámetro para asignar a la devolución de llamada de Perl
Un hash es un mecanismo ideal para almacenar el mapeo entre C y Perl.

Suplente Apilar Manipulación
Aunque solo he utilizado las macros "POP *" para acceder a los valores devueltos por Perl
subrutinas, también es posible omitir estas macros y leer la pila usando el "ST"
macro (Ver perlxs para una descripción completa de la macro "ST").

La mayoría de las veces, las macros "POP *" deberían ser adecuadas; el principal problema con ellos es que
lo obligan a procesar los valores devueltos en secuencia. Puede que esto no sea lo más
forma adecuada de procesar los valores en algunos casos. Lo que queremos es poder acceder a la
apilar en un orden aleatorio. La macro "ST" como se usa al codificar un XSUB es ideal para esto
propósito.

El siguiente código es el ejemplo que se da en la sección Volviendo a Lista of Valores recodificado a
utilice "ST" en lugar de "POP *".

hoyo estatico
call_AddSubtract2 (a, b)
int a;
int b;
{
dSP;
hacha I32;
int cuenta;

INGRESAR;
GUARDARTMPS;

PUSHMARK (SP);
XPUSHs (sv_2mortal (newSViv (a)));
XPUSHs (sv_2mortal (newSViv (b)));
VOLVER;

count = call_pv ("Sumar restar", G_ARRAY);

ESPAÑA;
SP - = cuenta;
hacha = (SP - PL_stack_base) + 1;

si (cuenta! = 2)
croar ("Gran problema \ n");

printf ("% d +% d =% d \ n", a, b, SvIV (ST(0)));
printf ("% d -% d =% d \ n", a, b, SvIV (ST(1)));

VOLVER;
TMPS LIBRES;
SALIR;
}

Notas

1. Nótese que era necesario definir la variable "ax". Esto se debe a que el "ST"
macro espera que exista. Si estuviéramos en un XSUB no sería necesario definir
"hacha" como ya está definido para nosotros.

2. El código

ESPAÑA;
SP - = cuenta;
hacha = (SP - PL_stack_base) + 1;

configura la pila para que podamos usar la macro "ST".

3. A diferencia de la codificación original de este ejemplo, no se accede a los valores devueltos en
orden inverso. Entonces ST(0) se refiere al primer valor devuelto por la subrutina Perl
y "ST (cuenta-1)" se refiere al último.

Creamos y llamar an Anónimo Subrutina in C
Como ya hemos mostrado, "call_sv" se puede utilizar para invocar una subrutina anónima. Sin embargo,
nuestro ejemplo mostró un script de Perl que invoca un XSUB para realizar esta operación. Veamos
cómo se puede hacer dentro de nuestro código C:

...

SV * cvrv = eval_pv ("sub {print '¡No me encontrarás abarrotando ningún espacio de nombres!'}", TRUE);

...

call_sv (cvrv, G_VOID | G_NOARGS);

"eval_pv" se usa para compilar la subrutina anónima, que será el valor de retorno como
bueno (lea más sobre "eval_pv" en "eval_pv" en perlapi). Una vez que esta referencia de código está en
Por otra parte, se puede mezclar con todos los ejemplos anteriores que hemos mostrado.

LIGERO DEVOLUCIONES DE LLAMADA


A veces es necesario invocar la misma subrutina repetidamente. Esto suele suceder con un
función que actúa sobre una lista de valores, como la función incorporada de Perl ordenar(). Puedes pasar un
función de comparación para ordenar(), que luego se invocará para cada par de valores que
necesita ser comparado. El primero() y reducir() funciones de List :: Util siguen una similar
patrón.

En este caso, es posible acelerar la rutina (a menudo bastante) utilizando
la API de devolución de llamada ligera. La idea es que el contexto de la llamada solo necesita ser
creado y destruido una vez, y el sub puede llamarse arbitrariamente muchas veces en el medio.

Es habitual pasar parámetros utilizando variables globales (normalmente $ _ para un parámetro, o
$ ay $ b para dos parámetros) en lugar de a través de @_. (Es posible utilizar el mecanismo @_
si sabe lo que está haciendo, aunque todavía no existe una API compatible. Es también
inherentemente más lento.)

El patrón de llamadas de macro es así:

dMULTICALL; / * Declarar variables locales * /
I32 dame = G_SCALAR; / * contexto de la llamada: G_SCALAR,
* G_ARRAY o G_VOID * /

PUSH_MULTICALL (cv); / * Configurar el contexto para llamar a cv,
y establecer vars locales de forma apropiada * /

/* círculo */ {
/ * establece el (los) valor (es) de tus variables de parámetro * /
MULTICALL; / * Realiza la llamada real * /
} / * fin del ciclo * /

POP_MULTICALL; / * Derribar el contexto de llamada * /

Para ver algunos ejemplos concretos, consulte la implementación del primero() y reducir() funciones
de Lista :: Util 1.18. Allí también encontrará un archivo de encabezado que emula la API multicall
en versiones anteriores de perl.

Use perlcall en línea usando los servicios de onworks.net


Servidores y estaciones de trabajo gratuitos

Descargar aplicaciones de Windows y Linux

  • 1
    PostInstaladorF
    PostInstaladorF
    PostInstallerF instalará todos los
    software que Fedora Linux y otros
    no incluye por defecto, después
    ejecutando Fedora por primera vez. Su
    fácil para ...
    Descargar PostInstallerF
  • 2
    rastro
    rastro
    El proyecto strace se ha trasladado a
    https://strace.io. strace is a
    diagnóstico, depuración e instrucción
    rastreador de espacio de usuario para Linux. Esta usado
    para monitorear un...
    Descargar seguimiento
  • 3
    GUI de extracto de gMKV
    GUI de extracto de gMKV
    Una GUI para la utilidad mkvextract (parte de
    MKVToolNix) que incorpora la mayoría (si
    no todas) la funcionalidad de mkvextract y
    Utilidades mkvinfo. Escrito en C#NET 4.0,...
    Descargar gMKVExtractGUI
  • 4
    Biblioteca JasperReports
    Biblioteca JasperReports
    La biblioteca JasperReports es la
    el código abierto más popular del mundo
    inteligencia empresarial y generación de informes
    motor. Está completamente escrito en Java.
    y es capaz de ...
    Descargar la biblioteca JasperReports
  • 5
    Libros Frappe
    Libros Frappe
    Frappe Books es una fuente libre y abierta
    software de contabilidad de escritorio que es
    simple y bien diseñado para ser utilizado por
    pequeñas empresas y autónomos. Eso'...
    Descargar Libros de Frappé
  • 6
    Python numérico
    Python numérico
    NOTICIAS: NumPy 1.11.2 es la última versión
    que se hará en sourceforge. Ruedas
    para Windows, Mac y Linux, así como
    Las distribuciones fuente archivadas pueden ser cuatro...
    Descargar Python numérico
  • Más "

Comandos de Linux

Ad