简体   繁体   English

我们什么时候使用goto * expr; 在C?

[英]When do we use goto *expr; in C?

| GOTO '*' expr ';'

我还没有看到过这样的陈述,任何人都可以举个例子吗?

This is so called Labels as Values and represents one of the GCC extensions. 这就是所谓的标签作为值 ,代表了GCC扩展之一。


As an example, I've applied this extension to give an answer to Printing 1 to 1000 without loop or conditionals question: 作为一个例子,我已应用此扩展来给出没有循环或条件问题的打印1到1000答案

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

IIRC that's a GNU-ism for tail calls. IIRC是尾部调用的GNU主义。 Normally you'd leave that optimization to the compiler, but it can be useful when writing kernels or embedded device drivers. 通常,您会将该优化留给编译器,但在编写内核或嵌入式设备驱动程序时它非常有用。

That is GCC specific. 这是GCC的具体内容。 It is not standard C (either C89 or C99). 它不是标准C(C89或C99)。 (It would come in handy sometimes though, to be able to do computed gotos.) (虽然它有时会派上用场,但是能够做计算得到的。)

Similar to PrintMe() already given, here is my solution using a "jump table" solving the same problem except it can do an arbitary # of operations, in this case printf(). 类似于已经给出的PrintMe(),这里是我的解决方案,使用“跳转表”来解决相同的问题,除了它可以执行任意操作#,在这种情况下是printf()。 Note that the referenced labels must be local to the function. 请注意,引用的标签必须是函数的本地标签。

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

Like others have stated, it's a GNU C extension ( https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html ). 像其他人所说,它是GNU C扩展( https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html )。

In addition to the above uses, there is a use in Bypassing the return system, and manually handling function(s)'s epiloge. 除了上述用途之外,还有一种用途可以绕过返回系统,并手动处理函数的结果。

While the use cases for this are few and far between, it would be useful in writing a fully C-based Exception ABI. 虽然用于此的用例很少,但在编写完全基于C的异常ABI时会很有用。 The Exception ABI I wrote for a very legacy platform uses these to perform Longjumps without a buffer. 我为一个非常遗留的平台编写的异常ABI使用这些来执行没有缓冲区的Longjump。 (Yes I do reinstate the stack frame before hand, and I make sure that the jump is safe). (是的,我事先恢复了堆栈框架,我确保跳转是安全的)。

Additionally, it could be used for a "JSR" finally block, like in Java prior to java 7, where prior to the return, an explicit return label is stored, and then the finally block is executed. 另外,它可以用于“JSR”finally块,就像在Java 7之前的Java中一样,在返回之前,存储显式返回标签​​,然后执行finally块。 Same prior to any exception being thrown or rethrown (the documentation does not say anything about it not being valid in GNU C++, but I would probably not use it in C++ at all). 在抛出或重新抛出任何异常之前相同(文档没有说明它在GNU C ++中无效,但我可能根本不会在C ++中使用它)。

In general, the syntax should not be used. 通常,不应使用语法。 If you need local jumps, use explicit gotos or actual control blocks, if you need non-local jumps use longjmp if you have to, and exceptions in C++ where possible 如果你需要本地跳转,使用显式的getos或实际的控制块,如果你需要非局部跳转,你可以使用longjmp,并且尽可能使用C ++中的异常

Never. 决不。 It's not C. It is possible in "GNU C", but it's, as Paul commented, "one of the worst features of FORTRAN", "ported...into C", and thus should be Considered Harmful. 它不是C.它可能在“GNU C”中,但正如Paul所评论的那样,“FORTRAN最糟糕的特征之一”,“移植到C中”,因此应该被认为是有害的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM