成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

代碼安全性和健壯性:如何在if和assert中做選擇?

安全 應用安全
這篇文章分析了 C 語言中比較晦澀、模糊的一個概念,似乎有點虛無縹緲,但是的確又需要我們停下來仔細考慮一下。
  •  一、前言
  • 二、assert 斷言
  • 三、if VS assert
  • 四、總結

一、前言

我們在擼代碼的時候,經常需要對代碼的安全性進行檢查,例如:

1. 指針是否為空?

2. 被除數是否為 0?

3. 函數調用的返回結果是否有效?

4. 打開一個文件是否成功?

對這一類的邊界條件進行檢查的手段,一般都是使用 if 或者 assert 斷言,無論使用哪一個,都可以達到檢查的目的。那么是否就意味著:這兩者可以隨便使用,想起來哪個就用哪個?

這篇小短文我們就來掰扯掰扯:在不同的場景下,到底是應該用 if,還是應該使用 assert 斷言?

寫這篇文章的時候,我想起了孔乙己老先生的那個問題:茴香豆的“茴”字有幾種寫法?

似乎我們沒有必要來糾結應該怎么選擇,因為都能夠實現想要的功能。以前我也是這么想的,但是,現在我不這么認為。

成為技術大牛、拿到更好的offer,也許就在這些細微之間就分出了勝負。

二、assert 斷言

剛才,我問了下旁邊的一位工作 5 年多的嵌入式開發者:if 和 assert 如何選擇?他說:assert 是干什么的?!

看來,有必要先簡單說一下 assert 斷言。

assert() 的原型是:

  1. void assert(int expression); 

1. 如果宏的參數求值結果為非零值,則不做任何操作(no action);

2. 如果宏的參數是零值,就打印診斷消息,然后調用abort()。

例如下面的代碼:

  1. #include <assert.h> 
  2. int my_div(int a, int b) 
  3.     assert(0 != b); 
  4.     return a / b; 

1. 當 b 不為 0 時,assert 斷言什么都不做,程序往下執行;

2. 當 b 為 0 時,assert 斷言就打印錯誤信息,然后終止程序;

從功能上來說,assert(0 != b); 與下面的代碼等價:

  1. if (0 == b) 
  2.     fprintf(stderr, "b is zero..."); 
  3.     abort(); 

assert 是一個宏,不是一個函數

在 assert.h 頭文件中,有如下定義:

  1. #ifdef NDEBUG 
  2.     #define assert(condition) ((void)0) 
  3. #else 
  4.     #define assert(condition) /*implementation defined*/ 
  5. #endif 

既然是宏定義,說明是在預處理的時候進行宏替換。

從上面的定義中可以看到:

  1. 如果定義了宏 NDEBUG,那么 assert() 宏將不做什么動作,也就是相當于一條空語句:(void)0;,當在 release 階段編譯代碼的時候,都會在編譯選項中(Makefile)定義這個宏。
  2. 如果沒有定義宏 NDEBUG,那么 assert() 宏將會把一些檢查代碼進行替換,我們在開發階段執行 debug 模式編譯時,一般都會屏蔽掉這 NDEBUG 這個宏。

三、if VS assert

還是以一個代碼片段來描述問題,以場景化來討論比較容易理解。

  1. // brief: 把兩個短字符串拼接成一個字符串 
  2. char *my_concat(char *str1, char *str2) 
  3.     int len1 = strlen(str1); 
  4.     int len2 = strlen(str2); 
  5.     int len3 = len1 + len2; 
  6.     char *new_str = (char *)malloc(len3 + 1); 
  7.     memset(new_str, 0 len3 + 1); 
  8.     sprintf(new_str, "%s%s", str1, str2); 
  9.     return new_str; 

如果一個開發人員寫出上面的代碼,一定會被領導約談的!它存在下面這些問題:

  1. 沒有對輸入參數進行有效性檢查;
  2. 沒有對 malloc 的結果進行檢查;
  3. sprintf 的效率很低;
  4. ...

1. 使用 if 語句來檢查

  1. char *my_concat(char *str1, char *str2) 
  2.     if (!str1 || !str2)  // 參數錯誤 
  3.         return NULL
  4.          
  5.     int len1 = strlen(str1); 
  6.     int len2 = strlen(str2); 
  7.     int len3 = len1 + len2; 
  8.     char *new_str = (char *)malloc(len3 + 1); 
  9.      
  10.     if (!new_str)   // 申請堆空間失敗 
  11.         return NULL
  12.      
  13.     memset(new_str, 0 len3 + 1); 
  14.     sprintf(new_str, "%s%s", str1, str2); 
  15.     return new_str; 

2. 使用 assert 斷言來檢查

  1. char *my_concat(char *str1, char *str2) 
  2.     // 確保參數正確 
  3.     assert(NULL != str1); 
  4.     assert(NULL != str2); 
  5.      
  6.     int len1 = strlen(str1); 
  7.     int len2 = strlen(str2); 
  8.     int len3 = len1 + len2; 
  9.     char *new_str = (char *)malloc(len3 + 1); 
  10.      
  11.     // 確保申請堆空間成功 
  12.     assert(NULL != new_str); 
  13.      
  14.     memset(new_str, 0 len3 + 1); 
  15.     sprintf(new_str, "%s%s", str1, str2); 
  16.     return new_str; 

3. 你喜歡哪一個?

首先聲明一點:以上這 2 種檢查方式,在實際的代碼中都很常見,從功能上來說似乎也沒有什么影響。因此,沒有嚴格的錯與對之分,很多都是依賴于每個人的偏好習慣不同而已。

(1) assert 支持者

我作為 my_concat() 函數的實現者,目的是拼接字符串,那么傳入的參數必須是合法有效的,調用者需要負責這件事。如果傳入的參數無效,我會表示十分的驚訝!怎么辦:崩潰給你看!

(2)if 支持者

我寫的 my_concat() 函數十分的健壯,我就預料到調用者會亂搞,故意的傳入一些無效參數,來測試我的編碼水平。沒事,來吧,我可以處理任何情況!

這兩個派別的理由似乎都很充足!那究竟該如何選擇?難道真的的跟著感覺走嗎?

假設我們嚴格按照常規的流程去開發一個項目:

1. 在開發階段,編譯選項中不定義 NDEBUG 這個宏,那么 assert 就發揮作用;

2. 項目發布時,編譯選項中定義了 NDEBUG 換個宏,那么 assert 就相當于空語句;

也就是說,只有在 debug 開發階段,用 assert 斷言才能夠正確的檢查到參數無效。而到了 release 階段,assert 不起作用,如果調用者傳遞了無效參數,那么程序只有崩潰的命運了。

這說明什么問題?是代碼中存在 bug?還是代碼寫的不夠健壯?

從我個人的理解上看,這壓根就是單元測試沒有寫好,沒有測出來參數無效的這個 case!

4. assert 的本質

assert 就是為了驗證有效性,它最大作用就是:在開發階段,讓我們的程序盡可能地 crash。每一次的 crash,都意味著代碼中存在著 bug,需要我們去修正。

當我們寫下一個 assert 斷言的時候,就說明:斷言失敗的這種情況是不可以的,是不被允許的。必須保證斷言成功,程序才能繼續往下執行。

5. if-else 的本質

if-else 語句用于邏輯處理,它是為了處理各種可能出現的情況。就是說:每一個分支都是合理的,是允許出現的,我們都要對這些分支進行處理。

6. 我喜歡的版本

  1. char *my_concat(char *str1, char *str2) 
  2.     // 參數必須有效 
  3.     assert(NULL != str1); 
  4.     assert(NULL != str2); 
  5.      
  6.     int len1 = strlen(str1); 
  7.     int len2 = strlen(str2); 
  8.     int len3 = len1 + len2; 
  9.     char *new_str = (char *)malloc(len3 + 1); 
  10.      
  11.     // 申請堆空間失敗的情況,是可能的,是允許出現的情況。 
  12.     if (!new_str) 
  13.         return NULL
  14.      
  15.     memset(new_str, 0 len3 + 1); 
  16.     sprintf(new_str, "%s%s", str1, str2); 
  17.     return new_str; 

對于參數而言:我認為傳入的參數必須是有效的,如果出現了無效參數,說明代碼中存在 bug,不允許出現這樣的情況,必須解決掉。

對于資源分配結果(malloc 函數)而言:我認為資源分配失敗是合理的,是有可能的,是允許出現的,而且我也對這個情況進行了處理。

當然了,并不是說對參數檢查就要使用 assert,主要是根據不同的場景、語義來判斷。例如下面的這個例子:

  1. int g_state; 
  2. void get_error_str(bool flag) 
  3.     if (TRUE == flag) 
  4.     { 
  5.         g_state = 1; 
  6.         assert(1 == g_state); // 確保賦值成功 
  7.     } 
  8.     else 
  9.     { 
  10.         g_state = 0; 
  11.         assert(0 == g_state); // 確保賦值成功 
  12.     } 

flag 參數代表不同的分支情況,而賦值給 g_state 之后,必須保證賦值結果的正確性,因此使用 assert 斷言。

四、總結

這篇文章分析了 C 語言中比較晦澀、模糊的一個概念,似乎有點虛無縹緲,但是的確又需要我們停下來仔細考慮一下。

如果有些場景,實在拿捏不好,我就會問自己一個問題:

這種情況是否被允許出現?

不允許:就用 assert 斷言,在開發階段就盡量找出所有的錯誤情況;

允許:就用 if-else,說明這是一個合理的邏輯,需要進行下一步處理。

本文轉載自微信公眾號「IOT物聯網小鎮」,可以通過以下二維碼關注。轉載本文請聯系IOT物聯網小鎮公眾號。

 

責任編輯:武曉燕 來源: IOT物聯網小鎮
相關推薦

2023-11-17 11:55:54

Pythonretrying庫

2015-09-25 10:17:01

AWS合規性安全風險

2021-07-30 11:21:39

物聯網網絡安全IoT

2017-02-05 15:10:55

Option函數式編程代碼

2024-01-08 09:38:51

Java數據

2010-12-07 09:51:43

Linux安全性netfilteriptables

2009-11-06 09:59:55

2025-02-13 00:28:26

2023-06-01 15:17:17

2015-06-15 10:48:25

2023-11-17 12:29:57

API安全性零信任

2019-01-17 10:58:37

2023-12-27 14:50:10

2023-09-27 16:08:37

2010-06-03 15:23:48

2015-05-11 10:42:17

混合云性能混合云安全SLA

2013-09-18 09:13:16

BYOD安全BYOD自帶設備辦公

2016-03-14 12:36:29

2022-07-04 09:30:59

Kubernetes云安全

2020-11-24 07:32:02

物聯網
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 激情a| 国产欧美精品一区二区 | 国产成人福利在线 | 成人国产精品久久久 | 一区二区三区国产好的精 | 日韩在线视频一区二区三区 | 欧美久 | 久久区二区 | 精品粉嫩aⅴ一区二区三区四区 | 久久99国产精品 | 日韩成人精品视频 | 亚洲人成免费 | 欧美一区二区三区免费电影 | 天天弄天天操 | 日韩毛片视频 | 欧美一区二区黄 | 国产传媒在线观看 | 在线看片国产 | 日韩精品一二三 | 成人精品鲁一区一区二区 | www.精品一区| 国产精品视频一 | 日韩第1页 | 91美女在线观看 | 99pao成人国产永久免费视频 | 欧美成人一区二区三区片免费 | 在线播放国产视频 | 天天操夜夜骑 | 三级视频国产 | 国产午夜视频 | 天天爽网站 | 国产一区二区激情视频 | 亚洲一区二区三区免费在线观看 | 成人av在线网站 | 五月婷婷丁香 | 久国久产久精永久网页 | 91视频三区 | 久久久国产一区二区三区 | 精品在线一区二区三区 | 中文字幕一级毛片视频 | 精品日韩在线观看 |