C++ '\0'引发的小故事

前天在修复一个加密程序,过程是这样的:在 web 端别人用 php 加密,在底层我用 C++ 解密。使用的加密算法一样,原则上来说解密后的文件和加密前的文件是一样的才对。

因为密钥的不统一,耗费了我们很长时间(交流的不变,造成理解的不同)。最后他把加密后每个字段代表的含义,以及密钥生成后的二进制数据都给我发过来,终于解密后的文件和加密前的文件看起来相同了。因为数据比较大,用控制台看不方便,加上有一些是乱码(编码显示的问题),所以比对起来很麻烦,只能看一个大概。

所以我是这样做的:

// char * data = new ...
cout << data << endl; // 输出到控制台
// 输出到文件
FILE * pfile = fopen("output.txt", "w ")
fprintf(pfile, data);
fclose(pfile);

用 beyond compare 比对了一下解密后的文件和加密前的文件,惊奇的发现在解密之后的文件在前面部分和加密前的文件完全相同。但是解密后的文件只有 1k,就好像发生了截断,突然后面就没有数据了。 我重新断点追踪,调试。发现一切都很正常。我开始怀疑是加密算法的问题,可是加密算法都是网上开源的,公司之前也用过,总不会出问题吧?!

假如是你们,你们知道问题出在哪儿吗?你可能会说你们没看代码,怎么知道问题在哪儿?不对,代码我已经给你们了!

我无奈之下,找了一个可以显示 16 进制数据的文本编辑器,仔细的比对加密前,加密后,解密后的三个文件。加密后的文件格式完全符合。当我看到加密后输出文件截断处的 16 进制数据,我什么都明白了。

是 "00" ,也就是 '\0' 。

fprintf 是将 data 作为一个字符串输出的。遇到了 '\0' 就以为字符串已经结束了。

后来我换成 WriteFile 来输出(fwrite应该也可以的),问题解决。

一个 '\0' 耗费我整整一个下午的时间 ……

这个问题也提示我们调试的时候使用 cout ,printf, puts 等等字符串输出时,一定要注意字符串有没有可能有 '\0'。

Date: 2012-03-31 01:46:06

Author: JerryZhang