Створіть програму за допомогою одного простого GOTO


25

Комікс XKCD GOTO

Ваше завдання - створити найбільшу програму, яка може використовувати саме один GOTO, без якого вся програма (або принаймні величезний фрагмент) повинна бути повністю реструктурована. Оцінка зараховується як кількість висловлювань у вашому коді, які змінюють місця або знову вводяться (видалення висловлювань не додає до вашої оцінки), коли код реструктурується без GOTO (іншим дозволено оскаржити вашу реструктуризацію, подавши більше елегантний). Оскільки це кодове боулінг, виграє найвищий бал.

Примітка. Я не несу відповідальності за атаки велоцирапторів, намагаючись це завдання.


2
Одна Гото здається проблематичним. Кожен код C, про який я думаю, що використовує єдиний goto, може бути тривіально змінений, щоб використовувати структуровані конструкції. Кілька готів, однак ...
Pubby

@ Змагання Pubby, здається, є протилежним до двох існуючих рішень. Заміна gotoна switchздається можливою для обох.
угорен

@Pubby Скільки гот вам потрібно, щоб створити ефективне рішення? Якщо проблема, як заявлено на даний момент, неможлива, я можу створити альтернативну проблему.
Джо З.

Я думаю, вам дозволено вставляти мультфільм, якщо також є посилання.
luser droog

1
Це не кваліфікується, але я дійсно це зробив .
luser droog

Відповіді:


11

C fizzbuzz

Це рішення базується на ідеї переривань та мінливих змінних (лише gcc, вибачте). Програма встановлює таймер, який періодично називає основним, куди ми йдемо, в якому місці останнє виконання нашого обробника перерв (основного) сказало нам, що ми повинні.

Я ніколи раніше не використовував таймери або мінливі мітки, тому я думаю, що тут є багато.

#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;
}

runслід задекларувати volatile, інакше while(run)можна "оптимізувати" до while(1). Або замість цього просто перейти кудись, що дзвонить exit.
угорен

@ugoren Добре. Я ввімкнув оптимізацію (O1, O2 і Os), і всі вони порушили програму. На жаль, просто додавання "летючого" перед запуском, gotoloc та num не виправили це. Можливо, gcc не створений для оптимізації такого типу коду.
shiona

Визначення volatile int numпоза основним повинно це робити. З static, gcc вважає, що знає, хто може з цим возитися.
угорен

на жаль, я не можу створити gotoloc поза основним, або я міг би, але я повинен був би встановити його на нуль зовні, а потім скинути лише на початку головного, якщо він дорівнює нулю. І заклик статистики зникає. Тому я думаю, що найкраще сказати, що я використовую C погано, gcc правильно не оптимізує його, тому не намагайтеся.
shiona

5

Perl

Я не дуже добре в боулінгу, але підозрюю, що це може зацікавити ОП. Це сито Ератостена з використанням змінної goto. Якби це було «реконструйовано», я сумніваюся, що будь-яке з них було б багаторазовим, крім, можливо, перших кількох рядків. Коли сито закінчиться, всі залишилися 1s в @primesмасиві відповідають основним значенням.

Для додаткової розваги не використовуються оні, орси, тернарі, умовні умови або оператори порівняння будь-якого типу.

@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:

У випадку, якщо є якась плутанина щодо того, чому я публікую це тут, в окремому запитанні (зараз видалено), ОП заявила, що "це питання, яке він насправді хотів задати", але не знав, чи можливо .
примо

У випадку, якщо є якесь плутанина щодо того, яке питання я розмістив, це було питання про будівельний код, використовуючи лише GOTO, а не лише один.
Джо З.

1
@JoeZeng Спочатку у мене було три, але я зменшив його до одного, щоб це було також правильним рішенням цієї проблеми.
примо

3

С

Моє використання макросів, можливо, не робить його "одним ГОТО".
І це зовсім коротко, тому "повністю реструктуризованих" не багато.
Але ось моя спроба все одно.

Читає номер зі стандартного вводу, друкує його 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
Так, використання таких макросів не є "одним ГОТО". Але навіть тоді вам потрібно буде забезпечити реструктуризацію програми без використання GOTO. Видалення висловлювань не додає вашої оцінки.
Джо З.

Роздрукувати числовий модуль 3 буде просто, використовуючи « printfі» scanf. Оцінка вашого рішення, швидше за все, буде приблизно 2 або 3.
Джо Z.

1
Справедливий пункт. Я не можу подумати, чому хто-небудь хотів би запрограмувати щось, що друкується n%3таким чином. Це повинна бути програма, яка стає звивистою, коли GOTO видаляється , а не коли він вводиться .
Джо З.

2
"Чому?" не має значення для цього сайту - він повний дурних способів робити дурні речі. Якщо ви видалите goto, програма не працюватиме. Але що ви очікували - що програма видасться лише згодом?
угорен

1
За вилученням та подальшою реструктуризацією, так. Простим прикладом може бути використання goto для виривання декількох вкладених циклів.
Джо З.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.