【问题标题】:When do we use goto *expr; in C?我们什么时候使用 goto *expr;在 C?
【发布时间】:2011-03-16 20:16:18
【问题描述】:
| GOTO '*' expr ';'

我还没见过这样的说法,谁能举个例子?

【问题讨论】:

  • 我不知道是谁投票结束了这个问题,但这是一个完全合理的问题。
  • @Tomalak Geret'kal:可能有人认为,因为他们不认识语法,所以它一定不是有效代码。
  • 天哪,你的意思是有人将 FORTRAN 最糟糕的功能之一“COMPUTED GOTO”移植到了 C 语言中?
  • 顺便说一句:将 gcc 添加到标签中,因为这是 GNU 主义。
  • @EdS: 好像是这样 :) 我猜 bmargulies 的谎言得到了 4 票赞成。 [编辑:好吧,我想从技术上讲他没有撒谎]

标签: c gcc goto


【解决方案1】:

这就是所谓的 Labels as Values,代表 GCC 扩展之一。


例如,我已应用此扩展程序向answer 提出Printing 1 to 1000 without loop or conditionals 问题:

void printMe () 
{
    int i = 1;
    startPrintMe:
    printf ("%d\n", i);
    void *labelPtr = &&startPrintMe + (&&exitPrintMe - &&startPrintMe) * (i++ / 1000);
    goto *labelPtr;
    exitPrintMe:
}

【讨论】:

    【解决方案2】:

    IIRC 是用于尾调用的 GNU 主义。通常你会将优化留给编译器,但在编写内核或嵌入式设备驱动程序时它会很有用。

    【讨论】:

    • 我不相信这是关于 tail callsoptimizations 的东西,这只是一个 GCC 扩展,用于更通用的用途。跨度>
    • 我认为尾调用接近于该构造的唯一安全使用是有争议的。
    • 并不意味着这是他们的目的。
    【解决方案3】:

    这是 GCC 特定的。它不是标准 C(C89 或 C99)。 (不过,它有时会派上用场,以便能够执行计算的 goto。)

    【讨论】:

      【解决方案4】:

      与已经给出的 PrintMe() 类似,这是我使用“跳转表”解决相同问题的解决方案,但它可以执行任意 # 次操作,在本例中为 printf()。请注意,引用的标签必须是函数的本地标签。

      int print_iterate( int count )
      {
          int  i=0;
      
          void * jump_table[2] = { &&start_label , &&stop_label };
      
        start_label:
          printf( ++i );
          // using integer division: i/count will be 0 until count is reached (then it is 1)
          goto *jump_table[ i/count ]; 
      
        stop_label:
          return 0;
      }
      

      【讨论】:

      • 不幸的是,&&
      【解决方案5】:

      正如其他人所说,它是一个 GNU C 扩展 (https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html)。

      除了上述用途外,还有一个用途是绕过返回系统,并手动处理函数的结语。

      虽然这方面的用例很少而且相差甚远,但它在编写完全基于 C 的异常 ABI 时会很有用。我为一个非常旧的平台编写的异常 ABI 使用这些来执行没有缓冲区的 Longjumps。 (是的,我确实事先恢复了堆栈帧,并确保跳转是安全的)。

      此外,它可以用于“JSR”finally 块,就像在 java 7 之前的 Java 中一样,在返回之前,存储显式返回标签​​,然后执行 finally 块。在抛出或重新抛出任何异常之前也是如此(文档没有说明它在 GNU C++ 中无效,但我可能根本不会在 C++ 中使用它)。

      一般来说,不应使用该语法。如果您需要本地跳转,请使用显式 goto 或实际控制块,如果您需要非本地跳转,请在必要时使用 longjmp,并尽可能使用 C++ 中的异常

      【讨论】:

        【解决方案6】:

        从来没有。它不是 C。它在“GNU C”中是可能的,但正如 Paul 评论的那样,它是“FORTRAN 最糟糕的特性之一”,“移植到 C 中”,因此应该被认为是有害的。

        【讨论】:

        • 其实没有。甚至 C 的作者也认识到,在某些情况下,goto 实际上可能比 C 中的其他结构化控件更受欢迎。当然,continuebreak 在消除对 goto 的需求方面还有很长的路要走.一般建议仍然是:谨慎使用goto
        • @JeffSzuhay:这个答案并不是说 goto 被认为是有害的,而是说 GNU C 计算的 goto 是有害的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-10
        • 2021-09-07
        • 1970-01-01
        • 1970-01-01
        • 2014-12-30
        相关资源
        最近更新 更多