用一个简单的GOTO编写程序


25

XKCD GOTO漫画

您的任务是构建一个可以使用最大的GOTO程序,而没有该程序,则必须完全重组整个程序(或至少很大一部分)。分数计为代码中没有GOTO进行结构重组时更改位置新引入的语句的数量(删除语句不会添加到您的分数中)(允许其他人通过提供更多内容来挑战您的重组)优雅的一个)。因为这是代码保龄球,所以最高分获胜。

注意:通过尝试此挑战,我对迅猛龙袭击不承担任何责任。


2
一个单一的goto似乎有问题。我能想到的使用单个goto的每个C代码都可以微不足道地更改为使用结构化构造。但是,多个人……
Pubby

@Pubby的主张似乎与当前的两种解决方案背道而驰。更换gotoswitch两个似乎是可能的。
ugoren

@Pubby您需要多少个goto来创建可行的解决方案?如果当前陈述的问题是不可能的,那么我可以创建一个替代问题。
Joe Z.

我认为您也可以嵌入卡通漫画,只要也有链接即可。
luser droog

1
它没有资格,但是我确实做到了
luser droog

Answers:


11

C嘶嘶声

此解决方案围绕中断和标签变量(仅适用于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

@ugoren好点。我打开了优化(O1,O2和Os),所有这些都破坏了程序。不幸的是,仅在运行前添加“ volatile”,gotoloc和num并不能解决问题。可能是gcc不是为优化此类代码而构建的。
shiona 2013年

volatile int num在main之外定义应该这样做。使用static,gcc认为它知道谁可以惹它。
ugoren

不幸的是,我无法在main之外创建gotoloc,但是我必须将它设置为在main外部为零,然后仅在main的开头为零才能重置。并且吸引力统计数据逐渐消失。因此,我认为最好说的是我使用C的方式不好,gcc正确地没有正确地优化它,所以不要尝试。
shiona 2013年

5

佩尔

我不是很擅长打保龄球,但是我怀疑这可能会让OP感兴趣。这是使用可变goto的Eratosthenes筛。如果这是“重构的”,我怀疑除了前几行之外,其中任何一个都可以重用。筛分结束时,数组中所有剩余的1s 都@primes对应于素数。

为了增加乐趣,可以使用no,or,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会说:“这是他实际上想问的问题”,但不确定是否可能。
2013年

如果我对发布的问题有任何疑问,那就是关于使用GOTO而不是仅使用GOTO来构建代码的问题。
Joe Z.

1
@JoeZeng我最初只有3个,但我将其减少为1个,这样它也可以有效解决此问题。
2013年

3

C

我对宏的使用可能不会使其成为“一个转到”。
而且它很短,因此“完全重组”并不多。
但是无论如何,这是我的尝试。

从标准输入中读取一个数字,打印为模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”。但是即使那样,您仍需要在不使用GOTO的情况下提供程序的重组。删除语句不会增加您的分数。
Joe Z.

仅需使用printf和即可打印以3为模的数字scanf。您的解决方案的得分很可能是约2或3
乔Z.

1
有道理。我想不出为什么有人会想要编程n%3以这种方式打印的东西。它应该是一个在删除 GOTO时而不是在引入时变得令人费解的程序。
Joe Z.

2
“为什么?” 与这个网站无关-它充满了愚蠢的方式来做愚蠢的事情。如果删除goto,该程序将无法运行。但是您期望什么-该程序将仅因删除而变得混乱?
ugoren

1
通过拆除和随后的重组,是的。一个简单的示例可能是使用goto打破多个嵌套循环。
Joe Z.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.