使用memcpy()函数将无符号字符数组中的字节放入std::string中

14

我有一个std::string变量。我需要将一些来自无符号字符数组的字节放入其中。我知道第一个字节和长度。

我可以使用std::string::assign函数。我已经使用过了。

但是我想用memcpy函数以正确的方式解决这个问题。

std::string newString;
memcpy(&newString, &bytes[startIndex], length);

我知道这是错误的。我已经研究了一些使用std :: vector的想法。

请帮助我找到解决这个问题最优雅的方法。


4
您认为为什么assign()不是“正确的方法”? - Barry
“以正确的方式”是“我知道它是错误的”。 - crashmstr
@Barry 我想用两种不同的方法来解决它。我正在学习C++语言。而且找到这个解决方案对我来说很有趣 :) - Oleksandr Balabanov
@crashmstr 但可以使用memcpy解决。对于像我这样的学习者来说,这很有趣 :) - Oleksandr Balabanov
@Barry 如果 char 是有符号的, 那么从 unsigned charchar 的转换在一些平台上是由实现定义的。使用 memcpy 是一种可移植保留位模式的方式。 - Emile Cormier
3个回答

24

既然我们只是在构造字符串,那么有一个接受两个迭代器的std::string构造函数:

template< class InputIt >
basic_string( InputIt first, InputIt last, 
              const Allocator& alloc = Allocator() );

我们可以提供以下内容:

std::string newString(&bytes[startIndex], &bytes[startIndex] + length);

如果我们不是在构建字符串而是给现有字符串赋值,你仍然应该优先使用assign()。这正是该函数的作用:

oldString.assign(&bytes[startIndex], &bytes[startIndex] + length);

但是如果出于某些原因您真的坚持要使用 memcpy(),那么您需要确保字符串实际上具有足够的数据可供复制。然后只需使用 &str[0] 作为目标地址进行复制

oldString.resize(length); // make sure we have enough space!
memcpy(&oldString[0], &bytes[startIndex], length);

在 C++11 之前,技术上不能保证字符串在内存中是连续存储的,尽管实际上通常是这样做的。


不知道。看起来有人不喜欢任何答案。 - NathanOliver
我认为&bytes[startIndex + length]与你已有的代码更一致(没有由程序员执行的指针算术运算)。但是还有一个接受const char*和长度的字符串构造函数:std::string newString(&bytes[startIndex], length); - Ryan Haining
@RyanHaining OP曾表示bytesunsigned char,在这种情况下,该构造函数将不适用。至于另一点,则因人而异。 - Barry
错过了 unsigned。在这种情况下将其转换为 const char* 似乎是合法的,但也没什么大不了的。 - Ryan Haining
1
@RyanHaining &bytes[startIndex + length] 可能会导致溢出,因为它在获取地址之前就 访问 [startIndex + length] 处的元素。想象一个向量 {'T'}:[startIndex (0) + length (1)] 将访问索引 1 的元素 - 而该元素不存在。 - K. Biermann
显示剩余6条评论

1
你需要设置字符串的大小,以便有一个适当大小的缓冲区来接收数据,并将从 data() 得到的指针的常量性强制转换出来。
std::string newString;
newString.resize(length);
memcpy((char*)newString.data(), &bytes[startIndex], length);

当然,所有这些都属于未定义行为的范畴,但仍然是相当标准的。

-1

这是一种hack方法,正如你所说的不正确的方式,但由于STL保证std::string具有连续的存储空间,因此这是可能的:

std::string str(32, '\0');
std::strcpy(const_cast<char*>(str.data()), "REALLY DUDE, IT'S ILLEGAL WAY");

当然,您可以以相同的方式使用std::memcpy(我只是使用strcpy来复制空终止字符串)...
在您的情况下:
str.resize(length);
memcpy(const_cast<char*>(str.data()), bytes + startIndex, length);

如果你要复制的字符串超过32个字节呢? - Barry
1
当然,你应该“预调大小”以使字符串尺寸适合(注意,使用resize()而不是reserve()!) - Nevermore
3
为了阐明 Nevermore 所说的“非法方式”的含义:修改通过 data 访问的字符数组是未定义行为。不要这样做。 - Ryan Haining
从“STL保证std :: string具有连续存储”并不意味着您可以修改“data()”返回的内容。 - Slava
1
从“不遵循您可以修改data()返回的内容”实际上并不遵循我不能修改data()返回的内容。这个问题没有法律解决方案,我指出这是一个黑客技巧。你想看看像&front()而不是data()的另一个黑客技巧吗? - Nevermore

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