Crea un programa con un simple GOTO


25

El cómic XKCD GOTO

Su tarea es construir el programa más grande posible que use exactamente un GOTO, sin el cual todo el programa (o al menos una gran parte de él) debe ser completamente reestructurado. El puntaje se cuenta como el número de declaraciones en su código que cambian de lugar o se introducen nuevamente (eliminar las declaraciones no se agrega a su puntaje) cuando el código se reestructura sin el GOTO (otros pueden desafiar su reestructuración presentando un elegante). Como se trata de bolos de código, gana la puntuación más alta.

Nota: No reclamo ninguna responsabilidad por los ataques de velociraptor al intentar este desafío.


2
El único goto parece problemático. Cada código C que se me ocurra que use un solo goto se puede cambiar trivialmente para usar construcciones estructuradas. Múltiples errores sin embargo ...
Pubby

El reclamo de @ Pubby parece sostenerse contra las dos soluciones actuales. Reemplazar gotocon switchparece posible para ambos.
Ugoren

@Pubby ¿Cuántos goto necesitarías para crear una solución viable? Si el problema como se indica actualmente es imposible, puedo crear un problema alternativo.
Joe Z.

Creo que puedes insertar la caricatura, siempre que haya un enlace también.
luser droog

1
No califica, pero realmente hice esto .
luser droog

Respuestas:


11

C fizzbuzz

Esta solución se basa en la idea de interrupciones y variables de etiqueta (solo gcc, lo siento). El programa configura un temporizador que periódicamente llama a main, donde vamos a cualquier lugar donde la última ejecución de nuestro controlador de interrupciones (main) nos indique que deberíamos hacerlo.

Nunca he usado temporizadores o variables de etiqueta antes, así que creo que hay mucho para jugar aquí.

#include <sys/time.h>
#include <signal.h>
#include <stdio.h>

int main(int argc)
{
    static int run = 1;
    static int* gotoloc = &&init;
    static int num = 0;
    static int limit = 50;

    goto *gotoloc;
init:
    signal(SIGVTALRM, (void (*)(int)) main);
    gotoloc = &&loop;

    struct itimerval it_val;

    it_val.it_value.tv_sec = 0;
    it_val.it_value.tv_usec = 100000;
    it_val.it_interval.tv_sec = 0;
    it_val.it_interval.tv_usec = 100000;
    setitimer(ITIMER_VIRTUAL, &it_val, NULL);

    while(run);

loop:
    num = num + 1;
    run = num < limit;
    gotoloc = &&notfizz + (&&fizz - &&notfizz) * !(num % 3);
    return 1;

fizz:
    printf("fizz");
    gotoloc = &&notbuzz + (&&buzz - &&notbuzz) * !(num % 5);
    return 1;

notfizz:
    gotoloc = &&notfizzbuzz + (&&buzz - &&notfizzbuzz) * !(num % 5);
    return 1;

buzz:
    printf("buzz\n");
    gotoloc = &&loop;
    return 1;

notbuzz:
    printf("\n");
    gotoloc = &&loop;
    return 1;

notfizzbuzz:
    printf("%d\n", num);
    gotoloc = &&loop;
    return 1;
}

rundebe declararse volatile, de lo contrario while(run)puede ser "optimizado" para while(1). O en su lugar, simplemente vaya a algún lugar que llame exit.
Ugoren

@ugoren Buen punto. Encendí las optimizaciones (O1, O2 y Os) y todos rompieron el programa. Desafortunadamente, solo agregando 'volátil' frente a la ejecución, gotoloc y num no lo arreglaron. Es posible que gcc no esté diseñado para optimizar este tipo de código.
shiona

Definir volatile int numfuera de main debería hacerlo. Con static, gcc piensa que sabe quién puede meterse con eso.
ugoren

desafortunadamente no puedo crear gotoloc fuera de main, o podría, pero tendría que ponerlo a cero afuera y luego reiniciarlo al comienzo de main si es cero. Y las estadísticas de apelación se desvanecen. Así que creo que es mejor decir que estoy usando C de una mala manera, gcc no lo optimiza correctamente, así que no lo intentes.
shiona

5

Perl

No soy muy bueno en los bolos, pero sospecho que esto puede interesar al OP. Este es un tamiz de Eratóstenes usando un goto variable. Si esto se 'refactorizara', dudo que algo sea reutilizable, aparte de las primeras líneas. Cuando finaliza el tamiz, todos los 1s restantes en la @primesmatriz corresponden a valores primos.

Para mayor diversión, no se usan ands, ors, ternaries, condicionales u operadores de comparación de ningún tipo.

@primes[2..1e4]=(1)x9999;
$a=2;
Y:
  $b=$a*~-$a;
X:
  $primes[$b+=$a+=$c=$a/100%2+$b/1e4%2]=0;
  goto"$c"^h;
Z:

En caso de que haya alguna confusión sobre por qué estoy publicando esto aquí, en una pregunta separada (ahora eliminada), el OP declaró que "esta era la pregunta que realmente quería hacer", pero no estaba seguro de si era posible .
primo

En caso de que haya alguna confusión sobre qué pregunta publiqué, fue una pregunta sobre la creación de código utilizando solo GOTO, en lugar de solo uno.
Joe Z.

1
@JoeZeng Originalmente tenía tres, pero lo reduje a uno para que también fuera una solución válida a este problema.
primo

3

do

Mi uso de macros quizás no lo convierte en "un GOTO".
Y es bastante corto, por lo que "completamente reestructurado" no es mucho.
Pero aquí está mi intento de todos modos.

Lee un número de la entrada estándar, lo imprime modulu 3.

int main() {
    char s[100], *p, r=0;
    void *pl[] = { &&a, &&b, &&c, &&d, &&e, &&f, &&g, &&h, &&i, &&j, &&a, &&b, &&x, &&y, &&z }, *p1;
    p = gets(s);
    #define N(n) (pl+n)[!*p*60+*p-48];p++;goto *p1
    a: p1=N(0);
    b: p1=N(1);
    c: p1=N(2);
    d: p1=N(0);
    e: p1=N(1);
    f: p1=N(2);
    g: p1=N(0);
    h: p1=N(1);
    i: p1=N(2);
    j: p1=N(0);
    z: r++;
    y: r++;
    x: printf("%d\n", r);

    return 0;
}

1
Sí, usar macros como ese no es "one GOTO". Pero incluso entonces, necesitaría proporcionar la reestructuración del programa sin usar un GOTO. Eliminar las declaraciones no aumenta su puntaje.
Joe Z.

Imprimir un número módulo 3 sería fácil con solo usar una printfy scanf. El puntaje de su solución probablemente sea de 2 o 3.
Joe Z.

1
Punto justo. Sin embargo, no puedo pensar por qué alguien querría programar algo que se imprima n%3de esa manera. Debe ser un programa que se vuelve complicado cuando se elimina el GOTO , no cuando se introduce .
Joe Z.

2
"¿Por qué?" es irrelevante para este sitio, está lleno de formas estúpidas de hacer cosas estúpidas. Si elimina goto, el programa no funcionará. Pero, ¿qué esperabas: que el programa se enredara solo con la eliminación?
ugoren

1
Por la eliminación y posterior reestructuración, sí. Un ejemplo simple podría ser el uso de goto para romper múltiples bucles anidados.
Joe Z.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.