如何将std :: string与接受char []缓冲区的Win32函数混合使用?

7

有许多 Win32 函数需要传递缓冲区的地址,例如 TCHAR[256],并将某些数据写入该缓冲区。它可能小于缓冲区的大小,也可能是整个缓冲区。

通常情况下,您会在循环中调用这个函数,例如从流或管道中读取数据。最终我想要高效地返回一个字符串,其中包含来自所有迭代调用的数据。我一直在考虑使用 std::string,因为它的 += 与 Java 或 C# 的 StringBuffer.append()/StringBuilder.Append() 方法类似,注重速度而不是内存。

但我不确定如何最好地将 std::string 与 Win32 函数混合使用,因为这些函数首先需要传递 char[]。有什么建议吗?

4个回答

11

如果参数是只读的,则要像这样使用std::string

std::string text("Hello");
w32function(text.c_str());
如果参数是输入/输出,请使用std::vector<char>代替,就像这样:
std::string input("input");
std::vector<char> input_vec(input.begin(), input.end());
input_vec.push_back('\0');
w32function(&input_vec[0], input_vec.size());
// Now, if you want std::string again, just make one from that vector:
std::string output(&input_vec[0]);

如果参数是只输出的话,使用std::vector<Type>如下:

// allocates _at least_ 1k and sets those to 0
std::vector<unsigned char> buffer(1024, 0);
w32function(&buffer[0], buffer.size());
// use 'buffer' vector now as you see fit

如果需要,您也可以使用std::basic_string<TCHAR>std::vector<TCHAR>

您可以在Scott Meyers的书Effective STL中了解更多有关此主题的内容。


6
相较于std::string,我建议使用std::vector,并在使用v.size()时使用&v.front()。请确保已经分配了空间!注意std::string和二进制数据之间的细节问题。
s += buf;//will treat buf as a null terminated string
s += std::string(buf, size);//would work

1
在构造函数中为向量设置初始大小或者调用 resize() 可能是明智的选择,然后将其 size() 作为缓冲区的长度传递。 - Idan K
@Mike Weller:感谢你的负评...我不明白你在这里的意图... .data() 怎么样?当然我知道 .c_str() 的作用,但是 OP 说函数需要一个缓冲区,对于任意二进制数据,使用 std::vector 要比使用 std::string 更好。 - Brian R. Bondy
请注意,您需要使用大小设置构造函数创建向量或对其调用resize()函数。 - Nikolai Fetissov
好的,那么你如何使用向量?我想调用例如Win32的ReadFile()函数,它需要LPVOID lpBuffer。你如何传递向量,以便ReadFile()将其附加到已有内容上?或者没有干净的方法可以做到这一点吗? - Leeks and Leaks
TCHAR缓冲区[256]怎么样?wstring ws; ws.append(buffer);?另外值得注意的是,被读取的数据是一个字符串。 - Leeks and Leaks
std::vector<char> vc(100); size_t x = (last read amount); ReadFile(..., vc.begin()+x, vc.size()-x,...);std::vector<char> vc(100); size_t x =(上次读取的数量); ReadFile(...,vc.begin()+x,vc.size()-x,...); - jmucchiello

6

std::string有一个函数c_str(),它返回它等效的C风格字符串(const char *)。

此外,std::string还有重载赋值运算符,可以将C风格字符串作为输入。

例如,假设ssstd::string实例,sc是C风格字符串,那么可以执行互换操作:

ss = sc; // from C-style string to std::string
sc = ss.c_str(); // from std::string to C-style string

更新:

正如Mike Weller指出的那样,如果定义了UNICODE宏,则字符串将是wchar_t*类型,因此您需要使用std::wstring代替。


1
请注意,TCHAR 的值将根据 UNICODE 宏的定义而改变。如果定义了 UNICODE,则字符串将为 wchar_t* 类型,您需要使用 std::wstring 来代替。 - Mike Weller
1
直接写入std::string的内部缓冲区可能是危险的,因为字符串还存储诸如长度之类的内容,如果这样做可能会无效。 - Idan K
Idan 是正确的。不要在将写入字符串缓冲区的函数中使用 std::string。 - jmucchiello
2
使用std :: string作为内存缓冲区是不正确的,因为当前标准不能保证其在内存中是连续的。 - Dmitry

2
  • 你需要一个兼容的字符串类型:typedef std::basic_string<TCHAR> tstring; 是一个不错的选择。

  • 对于只有输入参数的情况,可以使用 .c_str() 方法。

  • 对于缓冲区,选择略微不太清晰:

std::basic_string 不能保证像 std::vector 一样使用连续存储。然而,我见过的所有 std::basic_string 实现都使用连续存储,并且 C++ 标准委员会认为这个缺陷是标准中的一个缺陷。这个缺陷已经在 C++0x 草案中得到了修正。

如果你愿意稍微打破规则——没有负面影响——你可以使用 &(*aString.begin()) 作为指向长度为 aString.size() 的 TCHAR 缓冲区的指针。否则,现在你只能使用 std::vector。

以下是 C++ 标准委员会关于连续字符串存储的看法:

不规范化这种现有的做法并不会给实现者更多的自由。十年前我们曾这么想过。但是供应商们用他们的实现和在 LWG 会议上的声音说话了。无论标准怎么说,实现都会是连续的。因此,标准可能会给字符串客户更多的设计选择。


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