让我们来讨论另一个令人讨厌的数据类型——BSTR(基础字符串「Basic string」或者二进制字符串「binary string」)。
下面的代码选自VirtualBox项目。这段代码中的错误被PVS-Studio分析器诊断为:V745 一个'wchar_t *'类型的字符串被错误的转换为‘BSTR’字符串。可以考虑使用函数 'SysAllocString' 。
解释
BSTR是这样声明的:
让我们来讨论这个BSTR类型以对这个例子有一个更深的理解。
这个是MSDN site中BSTR的有关信息。读MSDN的文档确实不好玩,但不好玩也得做啊,是不?
BSTR (Basic string 或 binary string) 是COM,Automation和Interop函数所使用的一种字符串数据类型。在所有可以进入脚本的接口中都可以使用BSTR数据类型。BSTR的描述:
长度前缀。BSTR的前4个字节表示字符串长度。它的值不包含终止符null。
数据字符串。一个Unicode的字符串。可能会多次嵌入null字符。
终止符:两个null字符。
一个BSTR是一个指针。这个指针指向数据字符串的第一个字符,而不是长度前缀。BSTR用COM内存分配函数类分配内存,所以它们可以从函数中返回而无需考虑内存分配。
下面的代码是不对的:
这行代码可以正确构建(编译和链接),但是不会正确运行,因为这个字符串没有长度前缀。如果你用调试程序去检查这个变量的内存位置,你也不会在数据字符串前面找到一个4byte的长度前缀。所以,应该这样写:
现在定位这个变量的调试程序就能够找到一个包含值为34的长度前缀。是34而非17是因为前面有个‘L’修饰符,L把单字符(single-character)转换成了宽字符(single-character)。调试程序也能显示在数据字符串后面的2byte的终止符null。
COM函数的参数应该是BSTR,如果你用简单的Unicode字符串,COM函数会出错的。
我想这些已经足够你了解,为什么我们要区分BSTR和简单的"wchar_t *"字符串类型。
额外的链接:
MSDN.BSTR
StackOverfow. Static code analysis for detecting passing a wchar_t* to BSTR.
StackOverfow. BSTR to std::string (std::wstring) and vice versa.
Robert Pittenger. Guide to BSTR and CString Conversions.
Eric Lippert. Eric's Complete Guide To BSTR Semantics.
正确代码
建议
建议跟前面的一样。当你看到不认识的数据类型的时候,别慌,去看看文档。这很重要,所以这个建议再次出现也无须大惊小怪的。
下面的代码选自ReactOS项目。代码中包含的错误被PVS-Studio诊断为:V640 代码的运算逻辑跟它的格式不一致。一直在执行第二句。可能是少了花括号。
解释
代码有点长。幸运的是,它也比较简单,所以应该不难理解。
大意是这样的,如果你成功地通过_tstat64()函数得到了文件的信息,那就把数据放到of _stat结构体中。我们用宏stat64_to_stat来保存数据。
这个宏不能正确运行。它执行的操作没有用花括号{}包起来。结果就是,条件运算符体只是宏里的第一个字符串。如果你展开那个宏,你会看到:
因此,不管有没有正确收到信息,结构体里的成员都会被复制。
这肯定是个错误,但在实际中,它不是致命的。我们比较幸运,这里只是白白复制未初始化的内存单元而已。但我有遇到过更严重的错误,也跟宏编写不当有关。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课