没有完美的strcpy

strcpy的几个焦点集中在一下几点:

是否效率优先

NULL指针处理

重叠(源和目的相同是其一种特殊情况)处理

字符串结束字符

字符类型

效率优先版本

extern "C" char * unchecked_strcpy(char *d,const char *s )

{

   //the simplest and most efficient way

   assert(d && s);

   char* tmp = d;  

   while( *s)

      *tmp++ = *s++;

   *tmp = '/0';   

   return   d; 

}

这个版本已经没有什么好改动的地方了,在效率方面它可以得满分。注意extern “C”,不是随便写上去的,没错,它可以是一个C函数。作为一种低层程序库,完全有理由要求程序员自己控制好数组越界,空指针,野指针的情况,并将这些规格明确写于说明书上。

安全优先版本

extern "C" char * unchecked_strcpy_backward(char *d, const char *s )

{

   //the simplest and most efficient way

   assert(d && s);

 

   size_t size = strlen(s);

   char* tmp = d+size;

   s+=size;

 

   size++;

   while( size )

   {

      *tmp-- = *s--;

      --size;

   }

   return   d; 

}

 

 

extern "C" int strcpy_safe(char *d,

           const char *s )

{

   //return a exit code

   //handle the overlapping situation

 

   if(d == s)

      return 1;//source and destination are the same

 

   if(!d || !s)

      return 2;//null string

 

   size_t size = strlen(s);

 

   //non-overlapped

   if(d < s || d>s+size)

   {

      unchecked_strcpy(d,s);

      return 0;//no error

   }

 

   //overlapped

   unchecked_strcpy_backward(d,s);

   return 0;//no error

}

 

unchecked_strcpy_backward实现逆向字符串拷贝。

 

strcpy_safe,处理了几种常见的情况,所以这样的效率是不高的。当源和目的相同时直接返回错误码1,但是我们想想在实际情况中,这种概率又能有多高?串指向空时,直接返回错误码2。重叠时,逆向拷贝,然而逆向拷贝一定就是正确的结果吗?不见得。只是我们按照普通思维认为这是正确的。

 

即使这样,还有两个安全问题无法解决,源或目的字符串是野指针,目的字符串的缓冲区溢出。从理论上说,这两种情况超越了C++的控制。

 

所以,从安全意义讲,永远没有一个安全的strcpy实现。我们不本着信任程序员的态度开发程序,永远也没有安全可言,这样只会给自己带来无尽烦恼。

完全定制版本

template<typename char_type>

struct NonNullStringChecker

{

   static bool check(char_type* p1 , char_type* p2)

   {

      return true;

   }

 

   static void handle(char_type* p1 , char_type* p2)

   {

 

   }

};

 

 

template<typename char_type>

struct NonOverlappingChecker

{

   static bool check(char_type* d,char_type* s)

   {

      return false;

   }

 

   static void handle(char_type* d,char_type* s)

   {

 

   }

};

 

 

template<

   typename char_type = char,

   char_type end_char = '/0',

   class NullStringChecker = NonNullStringChecker<char_type>,

   class OverlappingChecker = NonOverlappingChecker<char_type>

>  

class strcpy_template

{

public:

   char_type* operator()(char_type* d, char_type* s)

   {

 

      if(!NullStringChecker::check(d,s))

        NullStringChecker::handle(d,s);

 

      if(OverlappingChecker::check(d,s))

      {

        OverlappingChecker::handle(d,s);

      }

      else

      {

        char_type* tmp = d;  

        while( *s != end_char)

           *tmp++ = *s++;

        *tmp=end_char;  

        return d;

      }

      return 0;

   }

};

 

是的,这是一个functor template,不是一个function template,因为function template不支持缺省参数。

 

从字符类型,字符串结束符号,空指针处理,重叠处理4个方面参数化这个类模版。当然,不能强迫所有人的模版技术都能达到Alexandrescu的水平(它把policy classmeta template programmingloki中运用的出神入化),所以必须提供一组缺省的参数给普通用户使用。

 

从程序看出NullStringCheckerOverlappingChecker都要提供checkhandle接口。为了更安全的目的,你可以在check中做出各种条件检查,并在handle中做处理或者抛出异常。

 

这个应该是最具有弹性的版本,如果面试者看重template技术,那么这个版本一定能得一个高分。

总结

没有完美的解决方案。

 

公司的考察编程风格,思维严密程度,语言细节等等都太片面。编程风格是个人问题,强迫别人改变是一种不礼貌和粗鲁的行为,从深层次看,是一种不尊重人权的做法。而思维严密无非就是做错误检查,难道效率和安全是矛盾的,这个道理没人明白?在没有要求效率或者安全优先的情况下,任何一种实现方法都是正确的。考察思维的严密程度使用这种方法实在是愚蠢至极。如果要考细节,我倒想问问他们一些问题:一个编译单元的定义是什么?成员函数模版全特化版本在没有被调用时,编译器会为其生成代码吗?export关键字的用途?

 

我同意侯捷的天下之事,必做于细。但是,在编程方面未必可以以小见大。Lippman的《Inside C++ Object》和Alexandrescu的《Modern C++ Design》错误频繁,仍然不影响是经典。Scott Meyers到现在还没有准备写《Effective Template》,仍然不影响他是一个大师。无聊的人才以细节定成败。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值