Oracle® Solaris Studio 12.4:C 用户指南

退出打印视图

更新时间: 2014 年 12 月
 
 

2.5 作为值的标签

C 编译器可识别称为计算转移 (computed goto) 语句的 C 扩展。使用计算转移 (computed goto) 语句能够在运行时确定分支目标。通过使用 '&&' 运算符可以获取标签的地址,并且可以将标签地址指定给 void * 类型的指针:

void *ptr;
...
ptr = &&label1;

后面的 goto 语句可以通过 ptr 转到 label1

goto *ptr;

由于 ptr 在运行时进行计算,因此 ptr 可以接受作用域内任何标签的地址,而 goto 语句可以转到该位置。

使用计算转移 (computed goto) 语句的一种方法是用于转移表的实现:

static void *ptrarray[] = { &&label1, &&label2, &&label3 };

现在可以通过索引来选择数组元素:

goto *ptrarray[i];

标签的地址只能通过当前函数作用域计算。尝试在当前函数外部获取标签的地址会产生不可预测的结果。

转移表和开关语句的作用相似,但转移表使跟踪程序流更加困难。明显的差别是,开关语句转移目标都在 switch 保留字的正向。使用计算转移 (computed goto) 实现转移表可在正向和反向启用分支。

#include <stdio.h>
void foo()
{
  void *ptr;

  ptr = &&label1;

  goto *ptr;

  printf("Failed!\n");
  return;

  label1:
  printf("Passed!\n");
  return;
}

int main(void)
{
  void *ptr;

  ptr = &&label1;

  goto *ptr;

  printf("Failed!\n");
  return 0;

  label1:
  foo();
  return 0;
}

以下示例也使用转移表控制程序流:

#include <stdio.h>

int main(void)
{
  int i = 0;
  static void * ptr[3]={&&label1, &&label2, &&label3};

  goto *ptr[i];

  label1:
  printf("label1\n");
  return 0;

  label2:
  printf("label2\n");
  return 0;

  label3:
  printf("label3\n");
  return 0;
}

%example: a.out
%example: label1

计算转移 (computed goto) 语句的另一个应用是作为线程代码的解释程序。解释程序函数内部的标签地址可以存储在线程代码中以便快速分发。