如何在C/C++中比较BSTR和字符串?

14
wprintf(L"Selecting Audio Input Device: %s\n", 
                            varName.bstrVal);

if(0 == strcmp(varName.bstrVal, "IP Camera [JPEG/MJPEG]"))...

以上报告:

error C2664: 'strcmp' : cannot convert parameter 1 from 'BSTR' to 'const char *'
5个回答

23

你需要使用wcscmp代替:

if(0 == wcscmp(varName.bstrVal, L"IP Camera [JPEG/MJPEG]"))
{
}

这里是BSTR数据类型的描述,它包含一个长度前缀和一个实际的字符串部分,其中只是一串WCHAR字符数组。此外,它还有两个NULL终止符。

需要注意的是BSTR数据类型的字符串部分可以包含嵌入的NULL值,因此wcscmp仅在BSTR不包含嵌入的NULL值的情况下工作(这可能是大多数情况)。


为什么有些函数前缀是 w,而有些是 wc - COMer
@COMer: 我不确定,但是wcs代表宽字符字符串。 - Brian R. Bondy
2
@COMer:我猜“str”会被替换为“wcs”(例如strcmp->wcscmp,strdup->wcsdup),但没有“str”的函数会在某个地方插入一个“w”(例如printf->wprintf,fopen->_wfopen)。 - wj32

1
作为 C 运行时的更丰富的替代方案,您可以在 Win32 中使用 Unicode CompareString 或 CompareStringEx API。如果您没有字符集问题需要考虑,那么 wcscmp 就可以了。

0

这里的所有其他答案要么完全错误,要么部分不正确,因为它们忽略了 BSTRstd::wstring 都可以包含多个嵌入的空字符。

这意味着它们不应该使用 wcscmp() 进行比较,因为它会在任一字符串中遇到第一个 \0 时停止比较。

以下是正确比较 BSTRstd::wstring 的方法:

// Windows.h defines min() and max() as macros
#define NOMINMAX

#include <Windows.h>
#include <string>

// std::string_literals namespace requires C++14,
// but it is needed only to construct strings with
// embedded nulls, not for the comparison itself
using namespace std::string_literals;

int wmain(int argc, wchar_t *argv[])
{
    std::wstring    String1 = L"I am a happy BSTR \0with \0embedded \0null chars"s;
    std::wstring    Temp = L"I am a happy bstr \0with \0embedded \0NULL chars"s;
    BSTR            String2 = SysAllocStringLen(Temp.c_str(), Temp.size());

    if (String2 == nullptr) {
        return ERROR_OUTOFMEMORY;
    }

    // make sure not to create a security vulnerability by
    // reading past the end of either buffer when comparing
    const size_t MaxCount = std::min(String1.size(), static_cast<size_t>(SysStringLen(String2)));

    bool Equal = wcsncmp(String1.c_str(), String2, MaxCount) == 0;

    if (Equal) {
        wprintf(L"Strings are equal\n");
    } else {
        wprintf(L"Strings are NOT equal\n");
    }

    SysFreeString(String2);

    return 0;
}

请注意,除非您使用_wcsnicmp()进行不区分大小写的比较,否则示例将打印“字符串不相等”。

0

我的解决方案:

static const std::wstring IPCamera = L"IP Camera [JPEG/MJPEG]";
if (varName.bstrVal == IPCamera {
  //...

尝试失败了。示例缺少一个右括号,我已经纠正了它(它编译通过),但逻辑不能将两个相同的字符串视为相等。 - trindflo

-1

我总是在BSTR周围构建_bstr_t包装器。这使得事情变得更加容易和符合惯用法:

if(std::string("IP Camera [JPEG/MJPEG]") ==
                   static_cast<const char*>( _bstr_t(varName.bstrVal) )
{
}

1
不是一个好主意:_bstr_t构造函数会在varName.bstrVal中制作一个完整长度的字符串副本。 - Sebastian
这也会将bstr从unicode转换为ANSI进行运行时转换,这是不必要的,因为你本来就可以首先与unicode文字比较。 - BrendanMcK

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