為什麼使用goto語句作錯誤處理

2021-08-14 12:22:33 字數 3504 閱讀 3309



2月22日,蘋果更新了ios7.0.6,修復了乙個bug,之後引起軒然大波,這個低階的bug會導致嚴重的安全問題.

這個bug很簡單,就是在**中多寫了一條goto fail語句,我們且不討論這個bug如何(有興趣的同學可以查閱文章末尾的鏈結),我們來討論另乙個問題.

稍微有一些linux驅動程式設計經驗的同學都知道,一般都會使用goto語句作錯誤處理,上大一的時候教c語言的老師就和我們說過,盡量少使用goto語句,這樣會增加程式的不穩定性,使得程式執行難以捉摸,那麼為什麼這麼喜歡使用goto語句作為錯誤處理呢.

我們來舉個簡單例子,我們來看兩份**:乙份不帶goto的錯誤處理的;乙份帶goto的錯誤處理的.一對比大家就清楚明了.

先來看乙份"普通版"的**:

[cpp]view plain

copy

print

? "font-size: 14px;">         

retval = request_irq(irq_eint(20), buttons_interrupt, irqf_disabled,   

"key1", (void *)eint_device_id);  

if(retval)  

/* driver register */

major = register_chrdev(major, driver_name, &key_fops);  

if(major < 0)  

key_class=class_create(this_module,driver_name);  

if(is_err(key_class))  

key_device=device_create(key_class,null, mkdev(major, minor), null,driver_name);  

if(is_err(key_device))

retval = request_irq(irq_eint(20), buttons_interrupt, irqf_disabled, 

"key1", (void *)eint_device_id);

if(retval)

/* driver register */

major = register_chrdev(major, driver_name, &key_fops);

if(major < 0)

key_class=class_create(this_module,driver_name);

if(is_err(key_class))

key_device=device_create(key_class,null, mkdev(major, minor), null,driver_name);

if(is_err(key_device))

看到了嗎.因為每一步的錯誤處理需要把之前申請或註冊成功的資源全部都釋放掉,比如class_create失敗需要登出irq和驅動(因為它們已經成功了,到這一步失敗了,那麼之前的成功就沒有意義了,所以因為一切要恢復到最初的樣子),所以這會產生大量重複的**,free_irq這個函式寫了三次,unregister_chrdev寫了二次,那咋辦呢?

請看我們文藝版的**.

[cpp]view plain

copy

print

? "font-size: 14px;">          

retval = request_irq(irq_eint(20), buttons_interrupt, irqf_disabled,   

"key1", (void *)eint_device_id);  

if(retval)  

/* driver register */

major = register_chrdev(major, driver_name, &key_fops);  

if(major < 0)  

key_class=class_create(this_module,driver_name);  

if(is_err(key_class))  

key_device=device_create(key_class,null, mkdev(major, minor), null,driver_name);  

if(is_err(key_device))  

__debug("register mydriver ok! major = %d\n", major);  

return 0;  

error_device:  

class_destroy(key_class);  

error_class:  

unregister_chrdev(major, driver_name);  

error_register:  

free_irq(irq_eint(20), (void *)eint_device_id);  

error:  

return retval;  

}

retval = request_irq(irq_eint(20), buttons_interrupt, irqf_disabled, 

"key1", (void *)eint_device_id);

if(retval)

/* driver register */

major = register_chrdev(major, driver_name, &key_fops);

if(major < 0)

key_class=class_create(this_module,driver_name);

if(is_err(key_class))

key_device=device_create(key_class,null, mkdev(major, minor), null,driver_name);

if(is_err(key_device))

__debug("register mydriver ok! major = %d\n", major);

return 0;

error_device:

class_destroy(key_class);

error_class:

unregister_chrdev(major, driver_name);

error_register:

free_irq(irq_eint(20), (void *)eint_device_id);

error:

return retval;

}

有了goto語句了,重複的**都可以省去了,錯誤處理的**只寫一次就可以了.每次錯誤處理只需把上一步的成功的資源給登出就可以了而不是像之前一樣需要把之前所有的都登出,這才是真正優雅的**呀!

但同時也不要忘了,在這裡使用goto,跳轉範圍都是init函式之內,在把控範圍之內,所以可以推薦使用.其它地方想使用的話,還是去回想c語言老師的話吧!

goto 語句的使用

goto語句包括兩個部分 goto和乙個標籤名稱。標籤的命名遵循與命名變數相同的約定。goto part1 標籤需要寫上工作的語句。part1 printf there is part1 n 觀察以下程式的執行結果 可以看到,當執行 goto 語句之後,程式就跳轉到part1 printf ther...

goto語句的使用

goto語句使用一定要在判斷中進行操作,如果再順序語句中,隨意的進行跳轉,那麼程式會具備極大的不確定性,比如前面定義了乙個變數,後面值已經改變了,然後goto又跳轉到定義處,那麼這個變數是定義的值還是後面改變的值?量大,這就不好控制了,所以一定要約束goto語句。include include in...

關於goto語句的使用

在專案中用到了大量的goto語句,遭到了領導的指責,感覺挺委屈的。作為乙個程式設計師,在很多地方都看到說要避免goto語句的使用。goto語句如洪水猛獸,其實都誤解了goto。濫用goto的確很恐怖,可是合理使用卻能夠對程式的結構效能有很大幫助。以下簡單說一下專案中用到goto的3類地方。1,多重迴...