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]; |
标签的地址只能通过当前函数作用域计算。尝试在当前函数外部获取标签的地址会产生不可预测的结果。
转移表和开关语句的作用相似(虽然存在某些主要差异),转移表使跟踪程序流更加困难。一个显著的差异是:开关语句转移目标全都从开关保留字开始正向转移;使用计算转移 (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) 语句的另一个应用是作为线程代码的解释程序。解释程序函数内部的标签地址可以存储在线程代码中以便快速分发。