1つの簡単なGOTOでプログラムを構築する


25

XKCD GOTOコミック

あなたの仕事は、プログラム全体(または少なくともその大部分)を完全に再構築しなければならないGOTOを1つだけ使用することができる最大のプログラムを構築することです。スコアは、GOTOなしでコードが再構築されたときに、場所変更したり、新しく導入された(ステートメントを削除してもスコアに追加されない)コード内のステートメントの数としてカウントされます(他のユーザーは、エレガントなもの)。これはコードボウリングなので、最高得点が勝ちます。

注:この挑戦を試みることによって、ヴェロキラプトル攻撃に対する責任を主張しません。


2
1つの後藤は問題と思われます。1つのgotoを使用するすべてのCコードは、構造化された構造を使用するように簡単に変更できます。複数のGOTOSしかし...
Pubby

@Pubbyの主張は、現在の2つのソリューションに反するようです。交換gotoでは、switch両方のために可能と思われます。
ウゴレン

@Pubby実行可能なソリューションを作成するために必要なgotoの数。現在述べられている問題が不可能な場合、別の問題を作成できます。
ジョーZ.

リンクがある限り、漫画を埋め込むことは許可されていると思います。
luser droog

1
資格はありませんが、実際にこれを行いました
luserはドローグ

回答:


11

C fizzbuzz

このソリューションは、割り込みとラベル変数(gccのみ、申し訳ありません)のアイデアを回避します。プログラムは、定期的にmainを呼び出すタイマーを設定します。ここで、割り込みハンドラー(main)の最後の実行が必要な場所に移動します。

私はタイマーやラベル変数を使用したことがないので、ここにはたくさんのことを考えています。

#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)をオンにすると、すべてがプログラムを中断しました。残念ながら、実行の前に「volatile」を追加しただけで、gotolocとnumは修正しませんでした。この種のコードを最適化するためにgccが構築されていない可能性があります。
塩奈

volatile int nummainの外部で定義する必要があります。でstatic、gccはだれがそれを台無しにできるかを知っていると考えます。
ウゴレン

残念ながら、メインの外部にgotolocを作成することはできません。または、外部にゼロに設定し、ゼロの場合にのみメインの先頭でリセットする必要があります。そして、アピールの統計は衰退します。だから、私はCを悪い方法で使用していると言うのが最善だと思う、gccは当然それを正しく最適化しないので、試さないでください。
塩奈

5

Perl

私はボウリングがあまり得意ではありませんが、これはOPに興味があるかもしれません。これは、変数gotoを使用したエラトステネスのふるいです。これが「リファクタリング」された場合、おそらく最初の数行を除いて、再利用可能になるとは思いません。Sieveが終了すると1@primes配列内の残りのsはすべて素数に対応します。

追加の楽しみのために、AND、OR、三項、条件、またはあらゆる種類の比較演算子は使用されません。

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

私がこれを別の質問(現在削除されている)でここに投稿する理由に関して混乱がある場合、OPは「これは彼が実際に尋ねたい質問でした」と述べましたが、それが可能かどうかはわかりませんでした。
プリモ

私が投稿した質問に混乱がある場合、それはただ1つではなくGOTO のみを使用してコードをビルドすることに関する質問でした。
ジョーZ.

1
@JoeZeng私はもともと3つありましたが、この問題に対する有効な解決策になるように1つに減らしました。
プリモ

3

C

私のマクロの使用法は、おそらく「1つのGOTO」にしません。
そしてそれは非常に短いので、「完全に再構築された」ことはそれほど多くありません。
とにかく、これが私の試みです。

標準入力から数値を読み取り、それを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
ええ、そのようなマクロを使用することは「1つのGOTO」ではありません。ただし、その場合でも、GOTOを使用せずにプログラムの再構築を行う必要があります。ステートメントを削除しても、スコアには追加されません。
ジョーZ.

3を法とする数値の印刷は、printfとを使用するだけで簡単になりscanfます。あなたのソリューションのスコアが最も可能性の高い2か3程度だろう
ジョー・Z.

1
公正なポイント。しかし、なぜだれかがそのように印刷する何かをプログラムしたいと思うのかは考えられませんn%3。GOTO が導入されたときではなく、削除されたときに複雑になるプログラムであるべきです。
ジョーZ.

2
"なぜ?" このサイトには無関係です-それは愚かなことをする愚かな方法でいっぱいです。を削除するgotoと、プログラムは動作しません。しかし、あなたは何を期待していました-削除だけでプログラムが複雑になるでしょうか?
ウゴレン

1
削除とその後の再構築により、はい。簡単な例としては、gotoを使用して複数のネストされたループから抜け出すことがあります。
ジョー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.