【编程好习惯】屏蔽编程语言特性

来源:互联网 发布:北宋 知乎 编辑:程序博客网 时间:2024/06/10 21:05

本文出自 “至简李云” 博客,请务必保留此出处http://yunli.blog.51cto.com/831344/228239

定义数组是做软件开发经常需要用到的最基本的编程语言功能之一,下面示例了采用数组保存一个会话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,即256时,就会造成数组写越界。为了修复这一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)可以采用一致的语义来编写程序,后继的维护人员可以很容易的理解,进而不容易出错。

这一编程习惯给我们的启示是:程序员在编写程序时,应当尽可能站在一个不懂编程语言特性的角度去思考。这种方式就是要求程序员不要将不同的语言(编成语言和通用的公共语言)混在一起,从而造成可读(维护)性问题。


0 0
原创粉丝点击