当前位置: 首页 > 工具软件 > goto > 使用案例 >

goto的理解与使用

卜飞鸣
2023-12-01

Goto

记得学C语言时,老师就有讲过:"不要使用goto, 这是一个坏习惯,而且很危险!"各类书籍上也是这么说,所以之前写的代码几乎从来没有使用过goto。
现在工作在搞Linux硬件驱动,内核源码里却有大量goto,看了些论坛大神的讨论,确实goto不应该多用,不然逻辑会搞得混乱。
但是自己也得会,不然内核代码也是看的稀里糊涂。

功能:

goto语句可以使程序在没有任何条件的情况下跳转到指定的位置。

直接上我的测试代码。
gototest.c

#include <stdio.h>
int main(void){
    char a;
cycle:
    printf("test goto\n");
    while(scanf(" %c",&a)){
        if('i' == a){
            printf("a = %d\n",a);
            goto in;
        }
        else if('c' == a){
            goto cycle;
        }
        else {
            printf("a = %d\n",a);
            goto out;
        }
   }
in:
printf("label_in!\n");

out:
printf("label_out!\n");

return 0;
}

测试:

hezaizai@ubuntu:~/code_test$ gcc gototest.c -o goto

hezaizai@ubuntu:~/code_test$ ./goto
test goto
i
a = 105
label_in!
label_out!
hezaizai@ubuntu:~/code_test$ ./goto
test goto
o
a = 111
label_out!
hezaizai@ubuntu:~/code_test$ ./goto
test goto
c
test goto
c
test goto
c
test goto
c
test goto
c
test goto
c
test goto
b
a = 98
label_out!

说明

1、输入i,goto in
2、输入o,goto out
3、输入c,goto cycle
4、如果goto了in,后面的out也一定会执行。换句话说,程序无论以哪种方式执行完毕都会执行out:。

PS

如果你够仔细,会发现在代码里while(scanf(" %c",&a)) %c之前有个空格。
为什么要这个空格呢?
复制我的代码,分别加和不加空格试下。
不卖关子了,是因为scanf语句吃掉回车或者空格,如果不加的话,循环是无效的。
建议还是跑下代码,感受下goto,和scanf()。

内核源码展示

static int omap3_l3_probe(struct platform_device *pdev)
{
	struct omap3_l3 *l3;
	struct resource *res;
	int ret;

	l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
	if (!l3)
		return -ENOMEM;

	platform_set_drvdata(pdev, l3);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "couldn't find resource\n");
		ret = -ENODEV;
		goto err0;
	}
	l3->rt = ioremap(res->start, resource_size(res));
	if (!l3->rt) {
		dev_err(&pdev->dev, "ioremap failed\n");
		ret = -ENOMEM;
		goto err0;
	}

	l3->debug_irq = platform_get_irq(pdev, 0);
	ret = request_irq(l3->debug_irq, omap3_l3_app_irq, IRQF_TRIGGER_RISING,
			  "l3-debug-irq", l3);
	if (ret) {
		dev_err(&pdev->dev, "couldn't request debug irq\n");
		goto err1;
	}

	l3->app_irq = platform_get_irq(pdev, 1);
	ret = request_irq(l3->app_irq, omap3_l3_app_irq, IRQF_TRIGGER_RISING,
			  "l3-app-irq", l3);
	if (ret) {
		dev_err(&pdev->dev, "couldn't request app irq\n");
		goto err2;
	}

	return 0;

err2:
	free_irq(l3->debug_irq, l3);
err1:
	iounmap(l3->rt);
err0:
	kfree(l3);
	return ret;
}

内核中一般使用goto来处理错误,也是有逻辑顺序的,上述代码如果正常不出错执行完,最后会依次执行err2、err1、err0标签里的代码。
自己可以顺着代码体会下。

 类似资料: