【问题标题】:Convert char to std::string not working将 char 转换为 std::string 不起作用
【发布时间】:2017-02-09 11:16:38
【问题描述】:

我正在尝试列出我的电脑的逻辑驱动器并将结果添加到向量中,但我得到了这个奇怪的result = ;;;

我在这里缺少什么?

std::vector<std::string> directory::getLogicalDrives() {
    DWORD mydrives = 100;
    char lpBuffer[100];
    DWORD drives = GetLogicalDriveStrings(mydrives, lpBuffer);

    std::vector<std::string> driveList;
    for (int i = 0; i < 100; i++) {
        std::string drive(3, '%c' + lpBuffer[0]); // Missing something?
        driveList.push_back(drive);
    }
    return driveList;
}

【问题讨论】:

  • 您是否尝试过使用调试器单步执行您的代码?
  • '%c' + lpBuffer[0] - 这应该怎么做?
  • '%c' + lpBuffer[0] 解析为; 时,lpBuffer[0] 的值是多少?
  • 阅读 getdrivestrings 的规范“一个指向缓冲区的指针,它接收一系列以空字符结尾的字符串,系统中每个有效驱动器一个,加上一个额外的空字符。每个字符串都是一个设备姓名。”。您没有处理格式的代码

标签: c++ winapi


【解决方案1】:

documentation 中所述,GetLogicalDriveStrings() 为您提供了一个以 NULL 结尾的字符串列表,该列表以 NULL 字符结尾。所以只需迭代该列表,例如:

std::vector<std::string> directory::getLogicalDrives() {
    std::vector<std::string> driveList;
    char szBuffer[105];
    DWORD size = GetLogicalDriveStrings(104, szBuffer);
    if ((size > 0) && (size <= 104)) {
        const char *pstr = szBuffer;
        while( *pstr ) {
            std::string drive( pstr );
            driveList.push_back(drive);
            pstr += (drive.length() + 1);
        }
    }
    return driveList;
}

【讨论】:

  • 这仅在您将项目设置为使用 MBCS 编码的情况下才有效。我知道没有不使用 Unicode 的正当理由。你应该打电话给GetLogicalDriveStringsW,用wchar_t替换char,用std::string替换std::wstring
  • @IInspectable 我回答了特定的 OP 问题,您应该建议替换为 OP,而不是我。
【解决方案2】:
DWORD mydrives = 100;
char lpBuffer[100];

100 个字符不够。从技术上讲,一台计算机最多可以有 26 个驱动器号(实际上,没有人同时拥有那么多驱动器号,但您仍然应该为此做好准备)。一个 100 个字符的缓冲区有足够的空间最多接收 24 个驱动器号字符串(4 * 24 + 1 = 974 * 25 + 1 = 101)。缓冲区中至少需要 105 个字符的空间才能接收 26 个驱动器号字符串 (4 * 26 + 1 = 105)。

std::string drive(3, '%c' + lpBuffer[0]); // Missing something?

这条线没有做你认为它做的事情。您正在考虑使用 C 风格的 sprint() 函数。您不能像这样使用带有std::string 的格式化字符串。这一行甚至不应该编译,或者应该在编译时出现警告。

此外,您甚至都没有正确循环输出字符串。 GetLogicalDriveStrings() 返回&lt;drive&gt;:\&lt;nul&gt; 格式的双终止字符串列表,其中&lt;drive&gt; 是列表末尾的&lt;nul&gt;。例如,如果返回驱动器 A、B 和 C,则缓冲区的内容将如下所示:

lpBuffer[ 0] = 'A';
lpBuffer[ 1] = ':';
lpBuffer[ 2] = '\\';
lpBuffer[ 3] = '\0';
lpBuffer[ 4] = 'B';
lpBuffer[ 5] = ':';
lpBuffer[ 6] = '\\';
lpBuffer[ 7] = '\0';
lpBuffer[ 8] = 'C';
lpBuffer[ 9] = ':';
lpBuffer[10] = '\\';
lpBuffer[11] = '\0';
lpBuffer[12] = '\0';

正确的方法是以 4 个字符为一组循环遍历缓冲区,直到到达最后的空终止符(不要忘记错误检查!),例如:

DWORD drives = GetLogicalDriveStrings(mydrives, lpBuffer);
if ((drives > 0) && (drives <= mydrives)) {
    char *pdrive = lpBuffer;
    while (*pdrive) {
        std::string drive(pdrive);
        driveList.push_back(drive);
        pdrive += 4;
    }
}

或者:

DWORD drives = GetLogicalDriveStrings(mydrives, lpBuffer);
if ((drives > 0) && (drives <= mydrives)) {
    for (int i = 0; i < drives; i += 4) {
        std::string drive(&lpBuffer[i]);
        driveList.push_back(drive);
    }
}

话虽如此,请考虑改用GetLogicalDrives(),这样您就不必担心为任何驱动器号字符串分配内存或循环:

DWORD drives = GetLogicalDrives();
if (drives) {
    char drive[] = "?:\\";
    for (int i = 0; i < 26; i++) {
        if (drives & (1 << i)) {
            drive[0] = 'A' + i;
            driveList.push_back(drive);
        }
    }
}

【讨论】:

  • 感谢这个很棒的解释知道出了什么问题。
猜你喜欢
  • 2010-11-14
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 2011-08-02
  • 2014-07-23
  • 2013-09-10
相关资源
最近更新 更多