suma - superponer graficas en r
¿Cómo "ir" a una función diferente en c? (4)
¿Pero qué hay de los niños? ¿apilar?
goto
entre funciones no tiene sentido si piensas en la pila. ¿Qué habrá en la pila cuando saltes? Las funciones de origen y destino podrían tener diferentes argumentos y un valor de retorno diferente. ¿A quién volverá la nueva función? ¿Su valor de retorno tendrá sentido para la persona que llama? La persona que llama llamó a la función fuente, no a la función destino.
¿Volver a llamar?
Considera tu ejemplo de cerca:
int main()
{
test();
main_next:
printf("hello, world);
}
void test()
{
goto main_next;
}
¿Qué sucede cuando se ejecuta el goto
? Supongo que querrías que esto salte la pila de regreso a la función de llamada main()
. El goto
sería efectivamente lo mismo que un return
, cambiando la pila de llamadas de:
main() main()
| to
+--> test()
Pero, ¿y si quisieras saltar a una función que no está en la pila de llamadas? ¿Entonces que?
O reemplazar la función actual?
Una interpretación diferente es que el goto
reemplazaría la llamada de test()
existente test()
por una a main()
. La pila de llamadas cambiaría de:
main() main()
| to |
+--> test() +--> main()
Ahora main()
se llama recursivamente a sí mismo, y el main()
inferior volverá al main()
, que, dicho sea de paso, espera un void
retorno void
pero va a recibir un int
.
setjmp y longjmp
Lo más cercano que puede obtener es con setjmp
/ longjmp
. Esto le permite guardar y restaurar el contexto de la pila para goto no local, lo que le permite saltar entre las llamadas a funciones.
setjmp
y longjmp
solucionan los problemas que describí (a) guardando y restaurando el contexto de la pila completa al saltar, y (b) no permitiendo saltos si el contexto de la pila ya no es válido. Cito de setjmp (énfasis mío):
setjmp () y longjmp (3) son útiles para tratar los errores y las interrupciones encontradas en una subrutina de bajo nivel de un programa. setjmp () guarda el contexto / entorno de la pila en env para su posterior uso por longjmp (3). El contexto de la pila se invalidará si la función que llamó a setjmp () regresa.
Para decirlo de otra manera, longjmp
es básicamente el equivalente en C de lanzar una excepción . Una función de bajo nivel puede desenrollar la pila de llamadas y reanudar la ejecución en una función de nivel mucho más alto.
También es tremendamente difícil de usar, y rara vez es una buena idea. De nuevo, desde la página man:
setjmp () y sigsetjmp () dificultan la comprensión y el mantenimiento de los programas. Si es posible, se debe usar una alternativa.
Básicamente estoy tratando de simular el código de ensamblaje en C.
Aquí está el código C:
int main()
{
test();
main_next:
printf("Hello, World!");
}
void test()
{
goto main_next;
}
Tratando de compilar este código (Linux 32 bit, gcc 4.6.3), obtuve este error:
error: label ‘main_randomtag_next’ used but not defined
¿Alguien sabe cómo hacer este tipo de goto interprocedimiento en C?
¡Gracias!
¡Bien, no puedo decir mejor que la sabiduría de http://c-faq.com/style/stylewars.html !
Básicamente, si quiere emular el comportamiento de ASM utilizando solo C, entonces debería usar todas las capacidades de ramificación de C / C ++. Y usar funciones y la pila de funciones es en realidad una mejora sobre gotos y etiquetas. ¡De eso se trata la programación estructurada, tal como lo dijo @ssg!
GCC genera el archivo de ensamblaje primero y solo luego lo ensambla, entonces, ¿qué hay de crear etiquetas usando el ensamblaje en línea?
void test()
{
__asm__ volatile (
"jmp main_next"
);
}
int main()
{
test();
__asm__ volatile (
"main_next:"
);
printf("hello, world");
}
Sin embargo, esto (obviamente) no debería usarse en casos reales, ya que no se ocupa en absoluto de la pila.
No está permitido saltar de una función dentro de otra. El problema es que la función "prueba" tiene una dirección de retorno en la pila y quizás un marco para las variables. Entonces, para hacerlo, debes limpiar el marco opcional y cambiar la dirección en la pila con la dirección de main_next:
Por lo tanto, en este ejemplo elemental, solo debe escribir en lugar de goto main_next return.
Pero en otros casos es un poco más complicado porque debes entender lo que quieres.
¿Necesita tener el código después de main_next: como si estuviera escrito en test ()? Debe recordar que los marcos variables locales de esas dos funciones son diferentes. Eso significa que si solo hace un salto, usará los nombres de las variables utilizadas en main, pero se referirá al marco de pila creado por test (). Eso significa que si los dos marcos no son compatibles, entonces pueden ocurrir cosas muy extrañas.
El problema es lo que quieres exactamente y por qué?
Si piensas solo en ensamblar y no usas variables en los marcos de pila, está bien. Pero, ¿qué vas a hacer sin variables?
Hay formas de hacer lo que quiere, pero debe decidir exactamente qué necesita y ¡puedo decirle cómo se puede hacer!