空BSTR和NULL BSTR之间应该有区别吗?

10

在维护COM接口时,空的BSTR是否应与NULL处理方式相同?换句话说,这两个函数调用是否会产生相同的结果?

 // Empty BSTR
 CComBSTR empty(L""); // Or SysAllocString(L"")
 someObj->Foo(empty);

 // NULL BSTR
 someObj->Foo(NULL);     
2个回答

14
是的 - 一个NULL BSTR与一个空BSTR是一样的。我记得当我们从VS6切换到2003时,发现了各种各样的错误 - CComBSTR类在默认构造函数方面有一个改变,使用NULL而不是一个空字符串进行分配。这种情况会发生在你将BSTR作为常规C样式字符串对待并将其传递给一些函数(如strlen),或者尝试用它初始化一个std::string时。
Eric Lippert在Eric's Complete Guide To BSTR Semantics中详细讨论了BSTR:

首先列出不同之处,然后逐点详细讨论每个问题。

  1. BSTR在NULL和""的语义上必须完全相同,而PWSZ在这些方面通常具有不同的语义。

  2. BSTR必须使用SysAlloc*函数族进行分配和释放。PWSZ可以是来自堆栈的自动存储缓冲区或使用malloc、new、LocalAlloc或任何其他内存分配器进行分配。

  3. BSTR长度固定,而PWSZ可以是任意长度,仅受其缓冲区中有效内存量的限制。

  4. BSTR始终指向缓冲区中的第一个有效字符,而PWSZ可能是指向字符串缓冲区中间或末尾的指针。

  5. 当为n字节BSTR分配空间时,你可以存储n/2个宽字符。当你为PWSZ分配n字节时,你可以存储n/2-1个字符 - 你必须留出空间来放置null。

  6. BSTR可以包含任何Unicode数据,包括零字符。而PWSZ除了作为字符串结束标记外,永远不会包含零字符。BSTR和PWSZ都有一个固定的长度,由其缓冲区中的字符数确定。

  • 在C字符串中,最后一个有效字符后必须为零;但在BSTR中,有效的字符可以是零字符。

  • BSTR实际上可能包含奇数个字节--它可以用于移动二进制数据。PWSZ几乎总是偶数个字节,并且仅用于存储Unicode字符串。


  • 4
    另一方面——我曾经遇到过不遵守 NULL == 空规则的 MSXML 代码,并且对这两者表现出不同的行为。但那是5年前的事情了(如果我没记错的话是 MSXML 3),希望现在他们已经解决了这个问题。 :-) - C. K. Young
    2
    .NET互操作也不遵守规则-它们将""转换为String.Empty,将NULL转换为null。 - JoeG
    从技术上讲,它们是不同的。它们是否将null视为空字符串取决于实现方式。请参见https://msdn.microsoft.com/en-us/library/cc237580.aspx。 - niks

    6

    处理这个问题的最简单方法是使用CComBSTR并检查.Length()是否为零。这适用于空值和NULL值。

    但是,请记住,必须释放空BSTR,否则将会有内存泄漏。最近我在别人的代码中发现了一些这样的问题。如果您没有仔细寻找,那么这些问题很难发现。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接