【问题标题】:Is in possible to do everything with goto's?有可能用 goto 做所有事情吗?
【发布时间】:2013-09-29 00:17:17
【问题描述】:

我知道 goto 是一种糟糕的设计实践。但是想象一下,我们被困在一个荒岛上,我们的工具箱里只有 goto 和 ifs。会不会这样:

    int i = 0;
    while (i < 10) i++; 

与此相同:

    int i = 0;
    loop: if (i < 10) { i++; goto loop; }

?

难道不是真的可以使用条件逻辑、分配/更改变量、方法调用和跳转来完成在 c# 中通常可以做的任何事情吗?

【问题讨论】:

  • 没有。如果编程是这样,我宁愿辞掉工作,做一个无家可归的乞丐
  • @HighCore 可能的。这就是装配的工作方式。是否实用?没有。
  • @colejohnson 对。不过,我的观点仍然存在
  • 嗯,是的,他们是平等的。但它也等于:int i = 10;.

标签: c# goto


【解决方案1】:

技术上?是的,一点没错。 Goto 程序正在完善,因此您可以将所有内容表示为它们。最后,机器代码与 goto 程序非常相似,因为循环和其他东西都是使用条件跳转完成的。当然,在 .NET 中,您将无法使用 only goto。在某些时候,您会遇到使用其他代码的地方不是这样编写的,或者您处于语言结构迫使您做其他事情的地方(创建类、方法、函数等)。但从技术上讲,是的。

但是你应该这样做吗?绝对不。 Goto 程序很难维护,并且当 C# 编译成使用跳转但在更高级别上的中间语言时,这样做可能会损失大量性能。此外,虚拟机可以在“正常”代码中进行很多优化,而当您将其放入固定的 goto-schema 时,它就无法优化。

顺便说一句。你的原始代码编译成这个 IL,本质上就是你使用 goto 编写的(我的注释):

// i = 0
IL_0001: ldc.i4.0                  // Load integer value 0 to stack
IL_0002: stloc.0   // i            // Store stack value in local variable 0

// goto loop-condition
IL_0003: br.s      IL_0009         // Jump to IL_0009

// loop-start:
// i = i + 1
IL_0005: ldloc.0   // i            // Load variable 0 to stack
IL_0006: ldc.i4.1                  // Load integer `1` to stack
IL_0007: add                       // Add top two stack values
IL_0008: stloc.0   // i            // Store result in local variable 0

// loop-condition:
// if (i < 10) { goto loop-start }
IL_0009: ldloc.0   // i            // Load variable 0 to stack
IL_000A: ldc.i4.s  0A              // Load integer `10` to stack
IL_000C: clt                       // Compare top two stack values
IL_000E: stloc.1   // CS$4$0000    // Store stack value in local variable 1
IL_000F: ldloc.1   // CS$4$0000    // Load variable 1 to stack
IL_0010: brtrue.s  IL_0005         // Jump to IL_0005 if stack value is true

【讨论】:

  • 如果您将自己限制在使用 goto 模拟标准控制结构(而不​​是像意大利面条一样跳来跳去),那么维护代码不会比具有适当控制结构的代码更难维护。
【解决方案2】:

是的,您可以重写任何程序以获得相同的输出,而无需使用任何循环。方法调用都可以内联,所以从技术上讲你也不需要这些。当然,类和接口对于任何逻辑也不是必不可少的。事实上,你可以用 if、goto、assignment 和 add 来做几乎所有事情。也许你甚至不需要那么多。

【讨论】:

    【解决方案3】:

    goto 本身并没有什么不好的地方。导致它不应该被使用的原因如下:

    • 极易被滥用,控制力强,使用得当;即便如此,它也会使代码更难阅读

    • 总是可以使用更具可读性的结构,例如 whiledoforforeach p>

    由于同时使用其他东西总是可能的并且总是更好,所以永远不应该实际使用goto

    我听说的一个可能的例外是打破深层嵌套:

    for (int x = 0; x < 100; x++)
       for (int y = 0; y < 100; y++)
          for (int z = 0; z < 100; z++)
             if (condition)
                goto end;
    end: ;
    

    VS

    for (int x = 0; x < 100, !condition; x++)
       for (int y = 0; y < 100, !condition; y++)
          for (int z = 0; z < 100, !condition; z++)
    

    为了更直接地回答您的问题,是的,完全可以使用gotos 而不是whiles、dos 等来完成所有控制流...我什至建议这样做会很好实践的挑战,但不是在任何真正的代码中,尝试在汇编中编码可能会是一种更好的学习体验,而不是强迫自己使用gotos。

    【讨论】:

      【解决方案4】:

      是的,这是可能的。最终,这就是装配的工作方式。装配中没有循环之类的东西。要更改代码中的位置,您必须使用等效的“goto”(通常是 jmp 或某种形式的“分支”)或函数调用(如果存在)。

      但是,如果我继承的代码库使用了gotos,我要么从头重写它,要么在不被允许的情况下退出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-25
        • 2021-03-02
        • 1970-01-01
        • 1970-01-01
        • 2011-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多