程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 【編程好習慣】屏蔽編程語言特性

【編程好習慣】屏蔽編程語言特性

編輯:關於C語言

定義數組是做軟件開發經常需要用到的最基本的編程語言功能之一,下面示例了采用數組保存一個會話ID的一段簡化代碼。

#define SESSION_ID_LEN_MIN  1
#define SESSION_ID_LEN_MAX  256

char g_SessionId [SESSION_ID_LEN_MAX];

int save_session_id (char *_session_id, int _length)
{
if (_length < SESSION_ID_LEN_MIN ||
       _length > SESSION_ID_LEN_MAX) {
return ERROR;
   }

   memcpy (g_SessionId, _session_id, _length);
   g_SessionId [_length] = '\0';

return SUCCESS;
}


如果仔細觀察將能發現上面的示例代碼中存在的一個bug,這個bug是當_length的值的大小剛好是SESSION_ID_LEN_MAX,即246時,就會造成數組寫越界。為了修復這一bug,可能會采用以下的方法。其中改動的出發點是判斷當_length的大小為SESSION_ID_LEN_MAX時,讓程序返回錯誤。

#define SESSION_ID_LEN_MIN    1
#define SESSION_ID_LEN_MAX    256

char g_SessionId [SESSION_ID_LEN_MAX];

int save_session_id (char *_session_id, int _length)
{
if (_length < SESSION_ID_LEN_MIN ||
       _length >= SESSION_ID_LEN_MAX) {
return ERROR;
   }

   memcpy (g_SessionId, _session_id, _length);
   g_SessionId [_length] = '\0';

return SUCCESS;
}


這段代碼從功能上來說沒有任何的問題,但其中存在一個可維護性的問題。這個問題就是改動後的“>=”造成的。

先拋開編程語言的語法,如果某個數學變量的最大值是Y,那麼Y是這個變量的有效值嗎?筆者的理解是:這個值應當是變量的有效取值。現在回頭看一看前面的改動,其中將最大值當作是一個無效的取值,這顯然違背了通常意義上對最大值的理解。

為什麼要指出這個“小小”的最大值問題呢?要知道一個好的編程習慣應盡可能地讓所編寫的程序的語義不會與讀者的常識相悖。對於上面更改後的代碼,當程序的讀者讀到“>=”時,很可能停下來思考一下“為什麼不能等於最大值呢?”。可以想象到的是,讀者得查看一下g_SessionId數組的大小是多少,然後“哦,這是因為數組的大小是SESSION_ID_LEN_MAX,但數組的定義將字符串中的結束符‘\0’也計算在內的,所以_length的大小不能等於SESSION_ID_LEN_MAX,否則,最後的那個結束符沒有地方放了”。

前面的程序所存在的一根本問題是將通常的公共語言與編程語言揉在了一起,從而造成所編寫出來的程序不容易理解,進而有可能造成維護上的麻煩。試想想,SESSION_ID_LEN_MAX應當包括最後的那個結束符嗎?我認為不應當包括,最後的結束符是從C語言的層面去看而存在的。那如何對程序做進一步的更改,從而提高可讀維護)性呢?下面是推薦的更好方法。

#define SESSION_ID_LEN_MIN    1
#define SESSION_ID_LEN_MAX    255

char g_SessionId [SESSION_ID_LEN_MAX + 1];

int save_session_id (char *_session_id, int _length)
{
if (_length < SESSION_ID_LEN_MIN ||
       _length > SESSION_ID_LEN_MAX) {
return ERROR;
   }

   memcpy (g_SessionId, _session_id, _length);
   g_SessionId [_length] = '\0';

return SUCCESS;
}


這一改動非常的簡單,就是在定義g_SessionId數組時,在其大小後面增加一個“+ 1”,用於消化掉C語言中的字符串應以‘\0’結束這一特性。另外,讓SESSION_ID_LEN_MAX減一以表示不包含字符串中的結束符。這種方法的好處是:
1)沒有違背公共語言中對最大值的理解,即最大值是一個可取的有效值。
2)可以采用一致的語義來編寫程序,後繼的維護人員可以很容易的理解,進而不容易出錯。

這一編程習慣給我們的啟示是:程序員在編寫程序時,應當盡可能站在一個不懂編程語言特性的角度去思考。這種方式就是要求程序員不要將不同的語言編成語言和通用的公共語言)混在一起,從而造成可讀維護)性問題。

本文出自 “至簡李雲” 博客,請務必保留此出處http://yunli.blog.51cto.com/831344/228239

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved