0

以下代码给出了空字符串和长度 = 0,但在调试时我可以看到 childDisplayName 具有正确的名称。

    CHAR fileSystemName[MAX_PATH + 1] = { 0 }; 
    DWORD serialNumber = 0; DWORD maxComponentLen = 0; 
    string childDisplayName = "";
    DWORD fileSystemFlags = 0; 
    if (GetVolumeInformationA("C:\\", // L"\\MyServer\MyShare\"
        (LPSTR)&childDisplayName, MAX_PATH+1,
        &serialNumber, &maxComponentLen,
        &fileSystemFlags, fileSystemName, sizeof(fileSystemName)) == true)
    {
        
        cout << childDisplayName << "length: "<<childDisplayName.length()<<endl;
    }


以下代码工作正常。我不明白为什么 LPSTR 在传递 char 数组时有效,而在传递字符串时却无效。

    CHAR fileSystemName[MAX_PATH + 1] = { 0 }; 
    DWORD serialNumber = 0; DWORD maxComponentLen = 0; 
    CHAR childDisplayName[MAX_PATH + 1] = { 0 };
    DWORD fileSystemFlags = 0; 
    if (GetVolumeInformationA("C:\\", // L"\\MyServer\MyShare\"
        childDisplayName, MAX_PATH+1,
        &serialNumber, &maxComponentLen,
        &fileSystemFlags, fileSystemName, sizeof(fileSystemName)) == true)
    {
        
        cout << childDisplayName << "length: "<<strlen(childDisplayName)<<endl;
    }
4

2 回答 2

1

string childDisplayName = "";创建一个空的空字符串(零大小和未指定的容量)。使用它作为数据缓冲区写入不太可能顺利。

您可以这样做:string childDisplayName(MAX_PATH + 1, ' ');创建一个分配了适当空间的字符串。

其次,正如@churill 所写,字符串的地址不是其中字符的地址。取而代之childDisplayName.data()的是用于获取char*可以写入的字符串的内部存储 - 但请确保不要写入范围之外[data(); data() + size())

编辑:关于如何std::string.data()工作的一点。

我做了一个小示例程序:

#include<iostream>
#include<string>

void print(const std::string& s)
{
    std::cout << "String size: " << s.size() << '\n';
    std::cout << "String contents: >>" << s << "<<\n";
    std::cout << "String as c-string: >>" << s.c_str() << "<<\n";
    std::cout << '\n';
}

int main() {
    std::string bla = "";
    auto bladata = bla.data();
    for (int i = 0;i < 5;++i) {
        bladata[i] = '!';
    }
    print(bla);

    std::string bla2(10, '\0');
    auto bla2data = bla2.data();
    for (int i = 0;i < 5;++i) {
        bla2data[i] = '!';
    }
    print(bla2);
}

运行此输出时:

String size: 0
String contents: >><<
String as c-string: >>!!!!!╠╠╠╠╠╠╠╠╠╠╠&lt;<

String size: 10
String contents: >>!!!!!     <<
String as c-string: >>!!!!!<<

这里发生了什么?首先要注意的std::string是创建了一个具有零大小和未指定容量的空- 查看我的调试器,我知道在我的系统上未指定容量为 15,所以只要我不超出该范围,就不会崩溃。但这显然不是您在实际代码中应该做的事情(在这里编写是严格未定义的行为)。

这意味着bla字符串的大小为 0,并包含一个 15 个字符的字符缓冲区,其中我将前 5 个字符设置为“!”。因此,当我尝试打印它size()或将其打印为 astd::string时,它与任何常规的空字符串相同。但是,如果我使用.c_str()直接打印内部缓冲区,那么它将打印为任何旧的char*,并且只打印内存中的任何内容,直到遇到空字符。

另一方面,bla2初始化为包含 10 个空字符。这意味着它的大小是 10,它的容量至少是10(在我的例子中它恰好也是 15)。这意味着在循环之后它仍然报告大小为 10,无论我将多少个 '!' 放入缓冲区,当我将其打印为 a 时,std::string它会打印它包含的所有 10 个字符;5 '!' 和 5 '\0'。但是,当我将其打印为 a 时,char*它会打印 5 个“!”,然后在遇到空字符时立即停止。

于 2020-08-06T12:03:49.657 回答
0

在第一个代码片段中,我无法获得 childDisplayName 的正确名称。

在此处输入图像描述

虽然看起来有几个字符,但是当我想输出它时触发了异常。

在此处输入图像描述

所以你传递了一个错误的地址给GetVolumeInformationA. 因为字符串的地址不是字符的地址

您可以像下面的代码一样进行测试:

string s("test");
CHAR cs[] = "test";
cout << (void*)&s << endl;
cout << (void*)&s[0] << endl;

cout << (void*)&cs << endl;
cout << (void*)&cs[0] << endl;

输出: 在此处输入图像描述

正如@churill 所说,std::string只管理一个动态的字符数组。所以你不能将字符串的地址传递给函数。

根据MSDN

如果修改数据的 const 重载返回的字符串的内容,则行为未定义。如果将终端空字符更改为任何其他值,您也会得到未定义的行为。如果对字符串的非常量引用传递给标准库函数,则返回的指针可能无效。它也可以通过调用非常量成员函数来使其无效。

所以即使你真的成功地传入childDisplayName.data()了函数。这也是一种未定义的行为。我建议你正确传递函数所需的参数类型,而不是试图传递其他未定义或无类型的行为,这会给你带来很多困惑。

于 2020-08-07T02:03:49.293 回答