Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否将n位从8位数组复制到64位整数?_C++_Algorithm_Bit Manipulation - Fatal编程技术网

C++ 是否将n位从8位数组复制到64位整数?

C++ 是否将n位从8位数组复制到64位整数?,c++,algorithm,bit-manipulation,C++,Algorithm,Bit Manipulation,我试图将uint8_ts数组的任意位置的n位复制到单个64位整数中。这是一个可行的解决方案,可以将任意数量的位复制到从数组开头开始的64位整数中,但我希望能够从数组的任何位置开始 例如,我可能想复制数组的第2位到第11位: {7,128,7} 用二进制表示,即: 00000111 1000000 00000111 我想要一个带值的整数: 0001111000 std::uint64_t key_reg(std::uint8_t* bytes, std::size_t n) { std::ui

我试图将uint8_ts数组的任意位置的n位复制到单个64位整数中。这是一个可行的解决方案,可以将任意数量的位复制到从数组开头开始的64位整数中,但我希望能够从数组的任何位置开始

例如,我可能想复制数组的第2位到第11位: {7,128,7}

用二进制表示,即: 00000111 1000000 00000111

我想要一个带值的整数: 0001111000

std::uint64_t key_reg(std::uint8_t* bytes, std::size_t n)
{
  std::uint64_t reg = 0;
  // The amount of bits that fit into an entire element of an array
  // ex, if I'm copying 17 bits, even_bytes == 2
  std::size_t even_bytes = (n - (n % 8)) / 8;
  // what's left over after the even bytes
  // in this case, remainder == 1
  std::size_t remainder = n - even_bytes * 8;

  // copy each byte into the integer
  for(std::size_t i = 0; i < even_bytes; ++i)
    if(remainder)
      reg |= (std::uint64_t)bytes[i] << (8 * (even_bytes - i));
    else
      reg |= (std::uint64_t)bytes[i] << (8 * (even_bytes - i - 1));

  // if there is an uneven number of bits, copy them in
  if(remainder) 
    reg |= (std::uint64_t)bytes[even_bytes];

  return reg;
}
我没想到会有人回答得这么快,所以这里有一个我用同样的方式提出的解决方案。我在stackoverflow上找到了这个bitfieldmask函数,但我找不到作者的问题

template<typename R>
static constexpr R bitfieldmask(unsigned int const a, unsigned int const b)
{
  return ((static_cast<R>(-1) >> (((sizeof(R) * CHAR_BIT) - 1) - (b)))
      & ~((1 << (a)) - 1));  
}

std::uint64_t key_reg(std::uint8_t* bytes, std::size_t pos, std::size_t n)
{
  std::uint64_t reg = 0;
  std::size_t starting_byte = (pos < 8) ? 0 : ((pos - (pos % 8)) / 8);
  std::size_t even_bytes = (n - (n % 8)) / 8;
  std::size_t remainder = n - even_bytes * 8;

  for(std::size_t i = 0; i < even_bytes; ++i)
    if(remainder)
      reg |= (std::uint64_t)bytes[starting_byte + i] << (8 * (even_bytes - i));
    else
      reg |= (std::uint64_t)bytes[starting_byte + i] << (8 * (even_bytes - i - 1));

  if(remainder) 
    reg |= (std::uint64_t)bytes[even_bytes];

  // mask out anything before the first bit
  if(pos % 8 != 0) {
    std::size_t a = n - pos;
    std::size_t b = n;
    auto mask = bitfieldmask<std::uint64_t>(a, b);

    reg = (reg & ~mask);
  }

  return reg;
}
模板
静态常量表达式比特域掩码(无符号整数常量a、无符号整数常量b)
{
返回((静态_-cast(-1)>>((sizeof(R)*字符位)-1)-(b)))
&我有以下几点

struct MyType
{
std::array<uint8_t, 892> m_rguID;
    uint16_t m_bitLength;


void GetBits(uint16_t startBit, uint16_t nBits, uint64_t & bits) const
};


void MyType::GetBits(uint16_t startBit, uint16_t nBits, uint64_t & bits) const
{
    if(startBit + nBits > m_bitLength)
        throw std::runtime_error("Index is out of range");
    uint32_t num1 = startBit % 8U;
    uint32_t num2 = 8U - num1;
    uint32_t num3 = nBits >= num2 ? num2 : nBits;
    uint32_t num4 = startBit >> 3;
    bits = (uint64_t)(((int64_t)((uint64_t)m_rguID[num4] >> (8 - num3 - num1)) & (int64_t)((1 << num3) - 1)) << (nBits - num3));
    uint32_t num5 = num4 + 1U;
    int num6 = nBits - num3;
    if(num6 <= 0)
        return;
    int num7 = num6 - 8;
    int num8 = 8 - num6;
    do
    {
        if(num6 >= 8)
        {
            bits |= (uint64_t)m_rguID[num5] << num7;
            ++num5;
        }
        else
        {
            bits |= (uint64_t)m_rguID[num5] >> num8;
            ++num5;
        }
        num6 += -8;
        num7 += -8;
        num8 += 8;
    } while(num6 > 0);
}
struct MyType
{
std::数组m_rguID;
uint16μt mμ比特长度;
无效获取位(uint16开始位、uint16开始位、uint64开始位和位)常量
};
void MyType::GetBits(uint16\u t startBit、uint16\u t nbit、uint64\u t&bits)常量
{
if(起始位+非起始位>m_位长度)
抛出std::runtime_错误(“索引超出范围”);
uint32_t num1=起始位%8U;
uint32_t num2=8U-num1;
uint32_t num3=nBits>=num2?num2:nBits;
uint32\u t num4=启动位>>3;
位=(uint64_t)((uint64_t)(uint64_t)m_rguID[num4]>>(8-num3-num1))和(int64_t)((10);
}

我认为复制所有必要的字节然后屏蔽额外的位更简单:

std::uint64_t key_reg(std::uint8_t* bytes, std::size_t n)
{
   std::uint64_t reg = 0;
   std::reverse_copy( bytes, bytes + n / 8 + ( n % 8 != 0 ), 
                      reinterpret_cast<char *>( &reg ) );
   reg >>= n % 8;
   reg &= ~( -1UL << n );
   return reg;
}

您的基本方法看起来不错。要处理不是8的倍数的位偏移,您只需先读取单个部分字节,然后继续执行其余部分:

uint64密钥注册(常量uint8字节、大小位置、大小){
const uint8_t*ptr=字节+位置/8;
uint64_t结果=0;
如果(位置%8>0){
/*读取第一个部分字节,屏蔽掉不需要的位*/
结果=*(ptr++)和(0xFF>>(位置%8));
如果(n>(8-位置%8-n);
}否则{
/*将请求的位计数减少为此字节获得的数字*/
n-=8-位置%8;
}
}
/*根据需要读取和移位尽可能多的整字节*/
而(n>=8){
结果=(结果0){
结果=(结果>(8-n));
}
返回结果;
}
通过一个简单的测试工具,演示了该代码在我能找到的所有边缘情况下都能正确工作,例如从字节中间开始读取完整的64位或仅读取单个字节的一部分(这实际上是一个非常特殊的情况,在单独的分支中使用上面代码中自己的
return
语句进行处理)

(注意我在C++中写了上面的代码,因为像你的原始代码一样,它并没有真正使用C++的任何特定的特性。


测试线束没有检查的一个特性,但我认为这段代码应该具备,就是它从输入数组中读取的字节数永远不会超过需要的字节数。特别是,如果
n==0
(虽然在数组开始后仍然会计算指向
pos/8
字节的指针)。

std::bitset
?您是否考虑过使用它?它必须将位转换为
无符号长
(至少64位的无符号整数类型)。我在数组{255,0,255}上测试了这一点从位置2开始,用15位,得到值111111,而不是1111110000000,我可能弄乱了endianness,让我修正一下that@SamG修正了,从你的代码中扣除字节的顺序并不简单,尽管你需要做更多的测试,如果你提供一些测试数据,我可以将其添加到ideone中
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t n)
{
   std::uint64_t reg = 0;
   std::reverse_copy( bytes, bytes + n / 8 + ( n % 8 != 0 ), 
                      reinterpret_cast<char *>( &reg ) );
   reg >>= n % 8;
   reg &= ~( -1UL << n );
   return reg;
}
std::uint64_t key_reg(std::uint8_t* bytes, std::size_t pos, std::size_t n)
{
   std::uint64_t reg = 0;
   auto endpos = pos + n;
   auto start = bytes + pos / 8;
   auto end = bytes + endpos / 8 + ( endpos % 8 != 0 );
   std::reverse_copy( start,  end, reinterpret_cast<char *>( &reg ) );
   reg >>= endpos % 8;
   reg &= ~( -1UL << n );
   return reg;
}