【问题标题】:Put bytes from unsigned char array to std::string using memcpy() function使用 memcpy() 函数将字节从 unsigned char 数组放入 std::string
【发布时间】:2015-12-23 14:24:28
【问题描述】:

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

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

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

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

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

请帮我找到最优雅的解决方案。

【问题讨论】:

  • 为什么你认为assign() 不是“正确的方式”?
  • “以正确的方式”是“我知道这是错误的” = ?
  • @Barry 我想用两种不同的方式解决它。我正在学习 C++ 语言。找到这个解决方案对我来说很有趣:)
  • @crashmstr 但可以使用 memcpy 解决。对我来说,像学习者这样的人很有趣:)
  • @Barry 从unsigned charchar 的转换是在签名char 的平台上实现定义的。 memcpy 将以可移植方式保留位模式。

标签: c++ stl memcpy unsigned-char


【解决方案1】:

由于我们只是在构造字符串,所以有一个 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(),那么你需要确保字符串实际上有足够的数据可以复制进去。然后使用&amp;str[0]作为目标地址复制到其中:

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

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

【讨论】:

  • IDK。看起来有人不喜欢任何答案
  • 我认为&amp;bytes[startIndex + length] 会更符合你所拥有的(没有程序员执行的指针运算)。但也有字符串 ctor 采用 const char* 和长度:std::string newString(&amp;bytes[startIndex], length);
  • @RyanHaining OP 曾说过 bytesunsigned char,在这种情况下构造函数将不适用。另一方面,YMMV。
  • 错过了unsigned。在这种情况下,强制转换为 const char* 似乎是合法的,嗯。
  • @RyanHaining &bytes[startIndex + length] 可能导致溢出,因为您在获取地址之前访问 [startIndex + length] 处的元素。想象一个向量 {'T'}: [startIndex (0) + length (1)] 将访问索引 1 处的元素——它不存在。
【解决方案2】:

这是一个 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只是为了复制以null结尾的字符串)...

在你的情况下:

str.resize(length);
memcpy(const_cast<char*>(str.data()), bytes + startIndex, length);

【讨论】:

  • 如果您要复制的字符串超过 32 个字节?
  • 当然,你应该'presize'合适的字符串(注意,resize()不是reserve()!)
  • 澄清 Nevermore 所说的“非法方式”是什么意思:Modifying the character array accessed through data is undefined behavior。不要这样做
  • from STL guarantees that std::string has contiguous storage 不跟随你可以修改 data() 返回的内容
  • 来自does not follow you can modify what data() returns 实际上不遵循我无法修改data() 返回的内容。这个问题没有合法的解决方案,我指出这是一个hack。你想看看像&amp;front() 这样的黑客攻击而不是data() 还是什么?
【解决方案3】:

您需要设置字符串的大小,以便有一个适当大小的缓冲区来接收数据,并将常量从您从data() 获得的指针中转换出来

std::string newString;
newString.resize(length);
memcpy((char*)newString.data(), &bytes[startIndex], length);

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

【讨论】:

    猜你喜欢
    • 2012-03-03
    • 2012-11-04
    • 2011-07-23
    • 2013-07-18
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    相关资源
    最近更新 更多