strcpy是众所周知的最危险函数之一,它不判断目标缓冲区是否足够长,而strncpy要好一点,但它从某种意义上讲,却比strcpy还危险方:当目标缓冲区满时,它不在尾部加零,也就是说,程序员也许会以为用了个安全的函数,结果拷贝过去的字串却可能不是以零结尾!!
这个函数的替代品是strsafe.h中的StringCchCopy()
二、危险且低效的sprintf()
sprintf(以及printf系列)不但危险,而且低效。首先,它与strcpy一样,没有判断目标缓冲区的长度,其次,它只能在运行时刻判断参数的类型和个数(也就是说,如果你的格式字符指定了“%s: %d”,但你传的参数个数不符,或者类型不符,只有在运行时刻才会爆发出来)。
从安全角度上讲,这个函数的替代品是strsafe.h中的StringCchPrintf(),但如果同时再考虑效率,用C++的输出流更好(比如ostringstream),因为输出流的格式化是在编译时刻决定的。
三、printf系列的错误用法(同样适用于StringCchPrintf
StringCchPrintf(outString, countOfOutBuffer, sourString)这种用法是相当危险的,它希望达到与StringCchCopy相同的效果,但它会在sourString中包含有“%d %s”这种程序员意料之外的冬冬时,产生严重的后果。正确的做法是:无论在任何情况下,printf系列函数都必须包含“明确的格式化字串”,比如sprintf(outString, "%s", sourString)。
四、貌似安全的strsafe.h中的系列函数
StringCchCopy等函数,有一个很讨厌的地方,就是它们不判断源字符指针是否为NULL,也就是说,如果我们传递一个NULL指针给它,希望它理解为一个空串,而它却会产生一个零地址访问违例。这个也许并不严重,但却会让漫不经心不仔细阅读文档的程序员大吃一惊,而我这里想说的是,这个并不是它们真正不安全的地方,真正不安全的地方其实在于它们并未把程序员从“必然管理字串长度和零结尾”中解脱出来,比方说程序员会提供一个错误的目标缓冲区长度,特别是在宽字符环境下,错误地传递了目标缓冲区的字节数,而不是字符数。
五、幸好有了STL
STL提供的模板类basic_string规避和解决了上述所有问题,让C++程序员也拥有了类似于DELPHI中的原生String,再配合输入输出流(输入流解决格式化输入问题、输出流解决了格式化输出),从此“必须管理字串及缓冲区长度”、“必须补零”等问题,不再是C++程序员需要考虑的了!
六、你还只是一个C程序员吗?
抛开OO不谈,如果你还在自己管理字符串,那你就还只是一个C程序员。(附注:不代表BS这门语言以及它的程序员们,只是在字符串这个软胁上,我们应该能做得更好)。