动态跳转到C中的标签

时间:2013-03-29 11:28:06

标签: c

我想显示输出 - 数字1到5,然后是无限的4-5。有什么方法可以传递i(4)的值而不是goto1中的字符i。或者是否有任何其他有效的方法来实现这一点,而没有说明开关中的所有选项(即案例1:goto1(c1)等)。

主要目的是跳转到一个语句在程序中计算的语句。

#define goto1(i) \
goto c##i

int main(){    
    c1 : printf(" num is 1 \n");
    c2 : printf(" num is 2 \n");
    c3 : printf(" num is 3 \n");
    c4 : printf(" num is 4 \n");
    c5 : printf(" num is 5 \n");

    int i=4;
    goto1(i);
}

5 个答案:

答案 0 :(得分:9)

如果你......冒险(或者我的意思是愚蠢?),你可以使用GCC扩展Labels as Values

  

6.3标签值

     

您可以使用一元运算符“&&”获取当前函数(或包含函数)中定义的标签的地址。该值的类型为void *。此值是常量,可以在该类型的常量有效的任何位置使用。例如:

 void *ptr;
 /* ... */
 ptr = &&foo;
     

要使用这些值,您需要能够跳转到一个。这是通过计算的goto语句 1 goto *exp;完成的。例如,

 goto *ptr;
     

允许使用void *类型的任何表达式。

     

使用这些常量的一种方法是初始化一个用作跳转表的静态数组:

 static void *array[] = { &&foo, &&bar, &&hack };
     

然后您可以选择带索引的标签,如下所示:

 goto *array[i];
     

请注意,这不会检查下标是否在C中的边界数组索引中从不这样做。

     

这样的标签值数组的用途与switch语句非常相似。 switch语句更干净,所以使用它而不是数组,除非问题不能很好地适应switch语句。

     

标签值的另一个用途是在线程代码的解释器中。解释器函数中的标签可以存储在线程代码中,以便进行超快速调度。

     

您可能无法使用此机制跳转到其他功能中的代码。如果你这样做,就会发生完全不可预测的事情。避免这种情况的最佳方法是仅将标签地址存储在自动变量中,而不将其作为参数传递。

     

编写上述示例的另一种方法是

 static const int array[] = { &&foo - &&foo, &&bar - &&foo,
                              &&hack - &&foo };
 goto *(&&foo + array[i]);
     

这对生活在共享库中的代码更友好,因为它减少了所需的动态重定位的数量,因此,允许数据是只读的。

     

如果内联或克隆包含函数,则同一标签的&&foo表达式可能具有不同的值。如果程序依赖于它们始终相同,则应使用__attribute__((__noinline__, __noclone__))来防止内联和克隆。如果在静态变量初始值设定项中使用&&foo,则禁止内联和克隆。

     

<小时/>   脚注

     

[1] Fortran中的类似功能称为指定goto,但该名称在C中似乎不合适,其中一个人可以做的不仅仅是在标签变量中存储标签地址。

在任何情况下都不应将其视为使用该功能的建议。计算出的goto最终从Fortran中移除;它最好留在历史的垃圾箱里。

答案 1 :(得分:5)

你要求跳桌吗?如果您使用的是gcc:它有一个跳转表机制。

#include <stdio.h>

int main()
{
    unsigned char data[] = { 1,2,3,4,5,4,5,0 };
    // data to "iterate" over, must be 0-terminated in this example

    void *jump_table[] = { &&L00, &&L01, &&L02, &&L03, &&L04, &&L05 };
    // you should fill this with all 256 possible values when using bytes as p-code

    unsigned char *p = data;

    begin:
        goto *jump_table[ *p ];

    L00:
        return 0; // end app
    L01:
        printf("num %i\n", (int)*p);
        goto next;
    L02:
        printf("num %i\n", (int)*p);
        goto next;
    L03:
        printf("num %i\n", (int)*p);
        goto next;
    L04:
        printf("num %i\n", (int)*p);
        goto next;
    L05:
        printf("num %i\n", (int)*p);
        goto next;
    L06:
    L07:
    // ...
    LFF:
        goto next;

    next:
        ++p;            // advance the data pointer to the next byte
        goto begin;     // start over

    return 0;
}

关于这种方法的专家是你省去了大的switch语句。

答案 2 :(得分:3)

为什么不这样做?

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf(" num is 1 \n");
    printf(" num is 2 \n");
    printf(" num is 3 \n");

    for (;;){
        printf(" num is 4 \n");
        printf(" num is 5 \n");
    }

    /* Not reachable, but will silence any compiler warnings about main
     * not returning a value. */
    return EXIT_SUCCESS;
}

答案 3 :(得分:1)

既然你想做错了(又名。创意)的方式,你有没有考虑过蹦床?

#include <stdio.h>

typedef void (*generic)(void);
typedef generic (*continuation)(void);

generic first(void);
generic second(void);

int main(void) {
    continuation fubar = first;
    for (;;) {
        fubar = (continuation) fubar();
    }
}

generic first(void) {
    printf(" num is 1 \n"
           " num is 2 \n"
           " num is 3 \n");
    return (generic) second;
}

generic second(void) {
    printf(" num is 4 \n"
           " num is 5 \n");
    return (generic) second;
}

继续从使用函数指针的想法(看看我在那里做了什么?Giggity!),你可以使用一个函数指针数组:

#include <stdio.h>

typedef size_t (*function)(size_t);

size_t first(size_t);
size_t second(size_t);

int main(void) {
    function function[] = { first, first, first, first, second };
    size_t index = 0;

    for (;;) {
        index = function[index](index);
    }
}

size_t first(size_t index) {
    printf(" num is %d \n", ++index);
    return index;
}

size_t second(size_t index) {
    printf(" num is %d \n", index+1);
    return index-1;
}

答案 4 :(得分:1)

开关不会完成同样的事情吗?

int main()
{
    int i = 1;
    while (1)
    {
        switch (i)
        {
            case 1:
                printf(" num is 1 \n");
            case 2:
                printf(" num is 2 \n");
            case 3:
                printf(" num is 3 \n");
            case 4:
                printf(" num is 4 \n");
            case 5:
                printf(" num is 5 \n");
            default:
                break;
        }

        // code to calculate i
        i = 4;
        // end code to calculate i
    }
    return 0;
}