我想显示输出 - 数字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);
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*ler 10
如果你......冒险(或者我的意思是愚蠢?),你可以使用GCC扩展标签作为值.
6.3标签作为价值观
您可以使用一元运算符'
&&' 获取当前函数(或包含函数)中定义的标签的地址.值有类型void *.此值是常量,可以在该类型的常量有效的任何位置使用.例如:Run Code Online (Sandbox Code Playgroud)void *ptr; /* ... */ ptr = &&foo;要使用这些值,您需要能够跳转到一个值.这是通过计算goto语句1,
goto *exp;.例如,Run Code Online (Sandbox Code Playgroud)goto *ptr;
void *允许任何类型的表达式.使用这些常量的一种方法是初始化一个用作跳转表的静态数组:
Run Code Online (Sandbox Code Playgroud)static void *array[] = { &&foo, &&bar, &&hack };然后您可以选择带索引的标签,如下所示:
Run Code Online (Sandbox Code Playgroud)goto *array[i];请注意,这不会检查下标是否在C中的边界数组索引中从不这样做.
这样的标签值数组的用途与switch语句非常相似.switch语句更干净,所以使用它而不是数组,除非问题不适合switch语句.
标签值的另一个用途是在线程代码的解释器中.解释器功能中的标签可以存储在线程代码中,以便进行超快速调度.
您可能无法使用此机制跳转到其他函数中的代码.如果你这样做,就会发生完全不可预测的事情.避免这种情况的最佳方法是仅将标签地址存储在自动变量中,而不将其作为参数传递.
编写上述示例的另一种方法是
Run Code Online (Sandbox Code Playgroud)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中删除; 它最好留在历史的垃圾箱里.
你在要求跳桌吗?如果你正在使用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;
}
Run Code Online (Sandbox Code Playgroud)
关于这种方法的专家是你省去了大的switch语句.