我可以使用STD ::复制将数据的位模式从整数向量复制到一系列未签名的字符

Can I use std::copy to copy bit pattern of data from vector of integers to an array of unsigned char

本文关键字:复制 字符 向量 一系列 整数 STD 可以使 数据 模式 我可以      更新时间:2023-10-16

最近我一直在尝试更新一些代码以利用标准的C 库功能,而不是旧的C样式函数。特别是,我尝试做以下(为简单起见的人为工作示例 - 我知道代码很丑陋,但它简单地说明了问题):

std::vector<int> vData;
vData.push_back(10990);
vData.push_back(11990);
vData.push_back(12990);
vData.push_back(13990);
unsigned char szBuffer[100];
memset(szBuffer,0,sizeof(szBuffer));
std::copy(vData.begin(),vData.end(),szBuffer);

我期望这将以与我要替换的代码相似的方式行为:

memcpy(szBuffer,&vData[0],sizeof(int)*vData.size());

但要调试代码,很明显,我编写的std::copy代码仅写入unsigned char缓冲区的前4个字节,而不是向量中4个整数的完整位模式。有人可以告诉我我做错了什么,还是简单地说我不能以这种方式使用std::copy并且应该坚持使用memcpy

坚持使用memcpystd::copy是智能的,它了解涉及的类型,并使用标准转换正确地将int转换为unsigned charmemcpy是无知的,这就是您想要的。

我期望这将以与我要替换的代码相似的方式行为...

书面的std::copy不能以与std::memcpystd::memmove相似的方式行为,因为std::vector<int>的元素与unsigned char szBuffer[100]的元素之间的类型不匹配。克服这种类型不匹配的一种方法是将szBuffer投射到int*

std::copy(vData.begin(),vData.end(),reinterpret_cast<int*>(szBuffer));

reinterpret_cast是个人喜好问题。我宁愿看到一些尖叫的东西"危险,危险,鲁滨逊!"对于可以在隐藏但不会消除UB潜力的C风格的铸件上调用不确定行为的事物。我(和我的项目经理霸主)可以为reinterpret_cast

UB的潜力是真实的,因为不能保证由于对齐问题而有效。

还请注意,不能保证std::copy将永远通过memcpymemmove实现。标准中没有一个单词(2003年或2011年)说std::copy需要通过memcpymemmove实现。(顺便说一句:在我看到的每个实施中,std::copy都将通过std::memmove实施,如果这样做的话,就好像"使用了"幼稚的实现"一样。)

std::memcpy切换到std::copy的唯一原因是美学。有时美学会阻碍。"愚蠢的一致性是小小的妖精。"我建议坚持使用std::memcpy。它完全可以做您想要的,并且此用法是安全的,因为没有重叠,并且由于缓冲区的尺寸适当。

,因为标准是行为(如果不是确切的实现) std::copy等于:

namespace std { 
  template< typename InIter, typename OutIter >
  OutIter std::copy( InIter begin, InIter end, OutIter outp )
  {
     for( ; begin != end; ++begin, ++outp )
     {
         *outp = *begin;
     }
     return outp;
  }
}

这意味着它会逐元复制成员,递增每个迭代器并返回输出中的下一个写入位置。

这与Memcpy不同,这是您在这里真正想要的。使用memcpy没有错(即使某个Microsoft编译器告诉您它是不安全的,它可能是,但是如果您不正确驾驶卡车,那就驾驶卡车,这并不意味着没有人可以开车一个)。

将向量的内容解释为原始内存,将 reinterpret_cast使用至 unsigned char *

std::copy(reinterpret_cast<unsigned char *>(&*vData.begin()),
          reinterpret_cast<unsigned char *>(&*vData.end()), szBuffer);

您需要间接并取下开始和结束元素的地址,因为不能保证vector::iterator是一种指针类型。

这是reinterpret_cast的少数保证安全用途之一。