我想显示输出 - 数字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);
}
答案 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;
}