c语言 goto lable 双取址(&&),动态goto的实现

goto 基本用法

#include <stdio.h>

int main(int argc,char* argv[])
{
	int *p = (int *)malloc(sizeof(int));
	if (!P) {
		goto error;
	}

	return 0;
error:
	return -1;
}

用法:

  • 给定一个标签名
  • 直接goto标签名

标签名地址获取

#include <stdio.h>

int main(int argc,char* argv[])
{
	void *p = NULL;
	void *perr = &&err;
	
lable:
    p = &&lable;
    printf("%p\n",p);

err:

	return 0;
}

获取地址直接使用 ’ && '即可。有两个特殊点

  • 在定义标记的后面,不能再定义局部变量。gcc报错为 “a label can only be part of a statement and a declaration is not a statement”
  • 获取标记地址没有要在标记后面的说法,如上例的 ‘perr’ 变量可以获取在它之后的标记地址

标记地址的作用

转成函数地址

标记地址是代码段的地址,可以试着当函数使用

#include <stdio.h>

int main(int argc,char* argv[])
{
    void (*p_fun)() = (void (*)())&&end;
    p_fun();

    printf("aaaaaaa\n");

end:
    printf("bbbbbbb\n");
    printf("aaaaaaa\n");
    printf("aaaaaaa\n");

	return 0;
}

输出:
bbbbbbb
aaaaaaa
aaaaaaa
这段代码堆栈没有平衡。只是测试标记地址

goto标记地址

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

int main(int argc,char *argv[])
{
    void *addr = &&end;
    goto *addr;

    printf("aaaaaaa\n");

end:
    printf("bbbbbbb\n");
    printf("aaaaaaa\n");
    printf("aaaaaaa\n");

    return 0;
}

要goto地址时,在保存地址变量加 ‘ * ’即可

动态goto

对比之前使用的goto,goto的使用是对应固定的标签。但我们可以把标签的地址保存在变量中,然后去goto这个变量,为动态goto提供了必要的条件。
动态goto的例子:

#include <stdio.h>                                                                                                                                                          
#include <string.h>

enum {
    ADD,
    SUB,
    MUL,
    DIV,
    END 
};

int main(int argc,char *argv[])
{
    static const void *const disptab[] = { 
        &&L_ADD,
        &&L_SUB,
        &&L_MUL,
        &&L_DIV,
        &&L_END
    };  

    int code[] = {ADD,ADD,MUL,MUL,END};
    int i = 0;
    int sum = 0;
    goto *disptab[code[i++]];
L_ADD:
    sum += 2;
    goto *disptab[code[i++]];
L_SUB:
    sum -= 2;
    goto *disptab[code[i++]];
L_MUL:
    sum *= 2;
    goto *disptab[code[i++]];
L_DIV:
    sum /= 2;
    goto *disptab[code[i++]];
L_END:
    printf("sum = %d\n",sum);

    return 0;
}                        

这段代码等价与

for()
{
	switch()
	{
	   	case ADD:
	   		sum += 2;
	   		break;
    	case SUB:
    		sum -= 2;
    		break;
    	case MUL:
    		sum *= 2;
    		break;
    	case DIV:
    		sum /= 2;
    		break;
    	case END:
	}
}

这个两段代码是仿照lua虚拟机的代码。在lua5.1采用的是for-switch,在最新的lua5.4采用的是动态goto。

参考:
lua5.4 goto代码
lua5.1 for-switch代码(GitHub上已经无5.1的代码可以在官网上下载整个源码)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值