[英]why passing string to a function which accepts LPSTR does noy work?
以下代码给出了空字符串和长度 = 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;
}
string childDisplayName = "";
创建一个空的空字符串(零大小和未指定的容量)。 使用它作为数据缓冲区写入不太可能 go 很好。
你可以这样做: string childDisplayName(MAX_PATH + 1, ' ');
创建一个分配了适当空间的字符串。
其次,正如@churill 所写,字符串的地址不是其中字符的地址。 而是使用childDisplayName.data()
将char*
获取到您可以写入的字符串的内部存储 - 但请确保不要写入范围[data(); data() + size())
[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: >>!!!!!╠╠╠╠╠╠╠╠╠╠╠<<
String size: 10
String contents: >>!!!!! <<
String as c-string: >>!!!!!<<
这里发生了什么? 首先要注意的是,一个空的std::string
是用零大小和未指定的容量创建的 - 在我的调试器中查看,我知道在我的系统上未指定的容量是 15,所以只要我不 go 之外什么都没有应该崩溃。 但这显然不是您在实际代码中应该做的事情(在这里编写是严格未定义的行为)。
这意味着bla
字符串的大小为 0,包含一个 15 个字符的字符缓冲区,我将前 5 个字符设置为“.”。 因此,当我尝试打印它的size()
或将其打印为std::string
时,它与任何常规的空字符串相同。 但是,如果我使用.c_str()
直接打印内部缓冲区,那么它将打印为任何旧的char*
并且只打印 memory 中的任何内容,直到遇到空字符。
另一方面, bla2
被初始化为包含 10 个空字符。 这意味着它的大小是 10,它的容量至少是 10(在我的例子中它恰好也是 15)。 这意味着在循环之后它仍然报告大小为 10,无论我将多少个 ',' 放入缓冲区,当我将其打印为std::string
时,它会打印它包含的所有 10 个字符; 5 '.' 和 5 '\0',但是,当我将其打印为char*
时,它会打印 5 '.',然后在遇到空字符时立即停止。
在第一个代码片段中,我无法获得 childDisplayName 的正确名称。
虽然它看起来有几个字符,但是当我想 output 时触发了异常。
因此,您将错误的地址传递给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
只管理一个动态的字符数组。所以你不能将字符串的地址传递给 function。
根据MSDN :
如果修改数据的 const 重载返回的字符串的内容,则行为未定义。 如果终端 null 字符更改为任何其他值,您也会得到未定义的行为。 如果对字符串的非常量引用传递给标准库 function,则返回的指针可能会失效。 它也可以通过调用非常量成员 function 来使其无效。
所以即使你真的成功地将childDisplayName.data()
传递到 function 中。 这也是一种未定义的行为。我建议您正确传递function所需的参数类型,而不是尝试传递其他未定义或无类型的行为,这会给您带来很多困惑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.