沒有完美的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》,仍然不影響他是一個大師。無聊的人才以細節定成敗。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章