新聞中心

EEPW首頁 > 設(shè)計(jì)應(yīng)用 > 嵌入式C中的goto語句,爭(zhēng)議很大

嵌入式C中的goto語句,爭(zhēng)議很大

作者: 時(shí)間:2024-03-21 來源:網(wǎng)絡(luò) 收藏

什么是

 被稱為 C 語言中的跳轉(zhuǎn),用于無條件跳轉(zhuǎn)到其他標(biāo)簽。它將控制權(quán)轉(zhuǎn)移到程序的其他部分。

本文引用地址:http://m.butianyuan.cn/article/202403/456669.htm

 語句一般很少使用,因?yàn)樗钩绦虻目勺x性和復(fù)雜性變得更差。

語法

goto label;

goto 語句示例

讓我們來看一個(gè)簡(jiǎn)單的例子,演示如何使用 C 語言中的 goto 語句。

打開 Visual Studio 創(chuàng)建一個(gè)名稱為:goto 的工程,并在這個(gè)工程中創(chuàng)建一個(gè)源文件:goto-statment.c,其代碼如下所示:

#include   void main(){  int age;gotolabel:  printf("You are not eligible to vote!n");  printf("Enter you age:n");  scanf("%d", &age);  if (age < 18)   {   goto gotolabel;  }  else  {   printf("You are eligible to vote!n");  }}

執(zhí)行上面代碼,得到以下結(jié)果

You are not eligible to vote!Enter you age:12You are not eligible to vote!Enter you age:18You are eligible to vote!

為什么它這么不受待見?

二十幾年前,當(dāng)計(jì)算機(jī)編程尚處于起步階段時(shí),程序流程是由 “GOTO” 語句來控制。該類語句允許程序員對(duì)當(dāng)前代碼行斷行,而直接進(jìn)入另一個(gè)不同的代碼段。

下圖為簡(jiǎn)單的示例。

640.png

編程語言終究開始引入了函數(shù)的概念,即允許程序?qū)Υa進(jìn)行斷行。如果已經(jīng)完成,不再使用 goto 語句來表示代碼的斷行。

函數(shù)調(diào)用后,函數(shù)將回到下一條指令。下圖為示例。

640-2.png

這一做法改善了程序結(jié)構(gòu),提高了可讀性。自此,這被視為編寫程序的正確方法。只要看到或想到 goto 語句,就會(huì)讓軟件工程師退縮,產(chǎn)生本能的厭惡。

在 wikipedia 上的解釋就是:

GOTO語句一直是批評(píng)和爭(zhēng)論的目標(biāo),主要的負(fù)面影響是使用GOTO語句使程序的可讀性變差,甚至成為不可維護(hù)的「面條代碼」。

隨著結(jié)構(gòu)化編程在二十世紀(jì)六十年代到七十年代變得越來越流行,許多計(jì)算機(jī)科學(xué)家得出結(jié)論,即程序應(yīng)當(dāng)總是使用被稱為「結(jié)構(gòu)化」控制流程的命令,以及 if-then-else 語句來替代 GOTO。甚至在今天,許多程序風(fēng)格編碼標(biāo)準(zhǔn)禁止使用 GOTO 語句。

也有不少人為 GOTO 語句辯護(hù),他們認(rèn)為只要加以限制地使用 GOTO 語句不會(huì)導(dǎo)致低質(zhì)量的代碼,并且在許多編程語言中,一些功能難以在不使用 GOTO 語句的情況下實(shí)現(xiàn)。比如有限狀態(tài)機(jī)的實(shí)現(xiàn)、跳出嵌套循環(huán)以及異常處理等等。

大概最著名的對(duì)于 GOTO 的批評(píng)是艾茲格·迪杰斯特拉(Edsger Wybe Dijkstra)在1968年的一篇名為《GOTO陳述有害輪》的論文。

迪杰斯特拉認(rèn)為不加限制地使用GOTO語句應(yīng)當(dāng)從高級(jí)語言中廢止,因?yàn)樗狗治龊万?yàn)證程序正確性(特別是涉及循環(huán))的任務(wù)變得復(fù)雜。

另外一種觀點(diǎn)出現(xiàn)在高德納的Structured Programming with go to Statements中,文章分析了許多常見編程任務(wù),然后發(fā)現(xiàn)其中的一些使用GOTO將得到最理想的結(jié)構(gòu)。

限制GOTO

許多語言,如 C 語言和 Java,提供了相關(guān)的控制流語句,如 break 和 continue,它們都是有效地被限制的 goto 語句。它們的作用是無條件跳轉(zhuǎn),但是只能夠跳到循環(huán)塊結(jié)束的位置 —— 繼續(xù)進(jìn)入下一循環(huán)(continue)或者結(jié)束循環(huán)(break)。

switch/case結(jié)構(gòu)

C 語言、C++ 和 Java 中的 switch 語句高效地實(shí)現(xiàn)了一個(gè)多路 goto,跳轉(zhuǎn)目標(biāo)由表達(dá)式的值來選擇。這也導(dǎo)致了我們沒有不得不使用 goto 的理由。

針對(duì)這些,導(dǎo)致目前 goto 的使用情況是這樣的:goto 語句的結(jié)果在C/C++等高級(jí)編程語言中保留了goto語句,但被建議不用或少用。

在一些更新的高級(jí)編程語言,如 Java 不提供 goto 語句,它雖然指定 goto 作為關(guān)鍵字,但不支持它的使 用,使程序簡(jiǎn)潔易讀;盡管如此后來的 c# 還是支持 goto 語句的,goto 語句一個(gè)好處就是可以保證程序存在唯一的出口,避免了過于龐大的 if 嵌套。

另一方面,goto 語句只是不提倡,當(dāng)然不是禁用,那么在什么情況下可以使用 goto 語句呢?

可以考慮使用 goto 的情形:

· 從多重循環(huán)中直接跳出 ;

· 出錯(cuò)時(shí)清除資源;

· 可增加程序的清晰度的情況。

不加限制地使用 goto:破壞了清晰的程序結(jié)構(gòu),使程序的可讀性變差,甚至成為不可維護(hù)的"面條代碼"。

經(jīng)常帶來錯(cuò)誤或隱患,比如它可能跳過了某些對(duì)象的構(gòu)造、變量的初始化、重要的計(jì)算等語句。

下列關(guān)于使用 goto 語句的原則可以供讀者參考。

1. 使用 goto 語句只能 goto 到同一函數(shù)內(nèi),而不能從一個(gè)函數(shù)里 goto 到另外一個(gè)函數(shù)里。

2. 使用 goto 語句在同一函數(shù)內(nèi)進(jìn)行 goto 時(shí),goto 的起點(diǎn)應(yīng)是函數(shù)內(nèi)一段小功能的結(jié)束處,goto 的目的 label 處應(yīng)是函數(shù)內(nèi)另外一段小功能的開始處。

3. 不能從一段復(fù)雜的執(zhí)行狀態(tài)中的位置 goto 到另外一個(gè)位置,比如,從多重嵌套的循環(huán)判斷中跳出去就是不允許的。

4. 應(yīng)該避免像兩個(gè)方向跳轉(zhuǎn)。這樣最容易導(dǎo)致"面條代碼"。

閱讀過 linux 內(nèi)核代碼的同學(xué)應(yīng)該注意到,linux 內(nèi)核代碼里面其實(shí)有不少地方用了 goto 語句,

這是在/drivers/i2c/i2c-dev.c中的i2c_dev_init函數(shù):

static int __init i2c_dev_init(void){ int res; pr_info("i2c /dev entries drivern"); res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c"); if (res)  goto out; i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); if (IS_ERR(i2c_dev_class))  {  res = PTR_ERR(i2c_dev_class);  goto out_unreg_chrdev; } i2c_dev_class->dev_groups = i2c_groups; /* Keep track of adapters which will be added or removed later */ res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); if (res)  goto out_unreg_class; /* Bind to already existing adapters right away */ i2c_for_each_dev(NULL, i2cdev_attach_adapter); return 0;out_unreg_class: class_destroy(i2c_dev_class);out_unreg_chrdev: unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);out: pr_err("Driver Initialisation failedn"); return res;}

但是你會(huì)發(fā)現(xiàn),這些地方的goto語句,使用非常謹(jǐn)慎,基本都遵循上面提到的幾個(gè)原則。

本文來源網(wǎng)絡(luò),免費(fèi)傳達(dá)知識(shí),版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請(qǐng)聯(lián)系我進(jìn)行刪除。



關(guān)鍵詞: 嵌入式 C語言 goto 語句

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉