c++ - 将 n 位从 8 位数组复制到 64 位整数?

标签 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::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;
}

你知道如何实现吗

std::uint64_t key_reg(std::uint8_t* bytes, std::size_t pos, std::size_t n);

我认为没有人会回答得这么快,所以这是我想出的相同风格的解决方案。我在 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;
}

最佳答案

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

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;
}

使用 pos 会稍微复杂一些:

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;
}

live example

关于c++ - 将 n 位从 8 位数组复制到 64 位整数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48310288/

相关文章:

algorithm - 计算器遵循什么样的算法来计算正弦值?

c - 使用按位运算符查找是否每个偶数位都设置为 0

c - 特定有限整数集的高效映射

c++ - 关于以二进制存储并显示其十进制

algorithm - 使用 4 个操作找到一对可以达到另一对的整数

c++ - 以二进制格式写入vtk文件

algorithm - 预先安排重复性任务

c - C 语言中的高效位屏蔽代码

c++ - 动态队列 C++

c++ - 如何在 Microsoft Visual C++.2010 Express 中链接 Lua?