Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.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++ 有没有更聪明的方法从比特数组中提取数据?_C++_C_Optimization_Bit Manipulation - Fatal编程技术网

C++ 有没有更聪明的方法从比特数组中提取数据?

C++ 有没有更聪明的方法从比特数组中提取数据?,c++,c,optimization,bit-manipulation,C++,C,Optimization,Bit Manipulation,我有可以被视为“位数组”的内存区域。它们相当于 unsigned char arr[256]; 但最好把它看作是 bit arr[2048]; 我正在使用 #define GETBIT(x,in) ((in)[ ((x)/8) ] & 1<<(7-((x)%8))) #define GETBIT(x,in)((in)[((x)/8)]&1如果您在“arr”中反转位顺序,那么您可以从宏中消除减法。这是我所能说的最好的,不知道问题上下文(位如何使用)。为什么不创建您自己

我有可以被视为“位数组”的内存区域。它们相当于

unsigned char arr[256];
但最好把它看作是

bit arr[2048];
我正在使用

#define GETBIT(x,in)   ((in)[ ((x)/8) ] & 1<<(7-((x)%8)))

#define GETBIT(x,in)((in)[((x)/8)]&1如果您在“arr”中反转位顺序,那么您可以从宏中消除减法。这是我所能说的最好的,不知道问题上下文(位如何使用)。

为什么不创建您自己的包装器类

然后可以使用+等运算符将位添加到“数组”中,并使用[]运算符返回各个位

使用&7而不是%8可以改进宏,但编译器可能会为您进行优化

我最近确实做了你正在做的事情,我的流可以由任意数量的比特组成

因此,我有如下几点:

BitStream< 1 > oneBitBitStream;
BitStream< 2 > twoBitBitStream;

oneBitBitStream += Bit_One;
oneBitBitStream += Bit_Zero;

twoBitBitStream += Bit_Three;
twoBitBitStream += Bit_One;
比特流<1>一比特流;
比特流<2>两比特流;
OneBitstream+=位1;
OneBitstream+=位0;
TwoBitStream+=位\三;
TwoBitStream+=位1;

等等。它有助于编写可读性很好的代码,您可以为它提供一个类似STL的接口来帮助实现相似性:)

我不这么认为。事实上,许多CPU架构不会单独访问位

<> C++上有<代码> STD::BITSESE。但根据编译器的实现和优化,可能没有最高的性能


顺便说一句,最好将您的位数组分组为
uint32\u t[32]
(或
uint64\u t[16]
)以进行对齐解引用(其中
bitset
已经为您做了这项工作)。

对于随机访问单个位,您建议的宏与您将要获得的宏一样好(只要在编译器中启用优化)

如果您正在访问的位有任何模式,那么您可能会做得更好。例如,如果您经常访问成对的位,那么您可能会看到一些改进,提供了一种获取两个位而不是一个位的方法,即使您不总是使用两个位

与任何优化问题一样,您需要非常熟悉代码的行为,特别是位数组中的访问模式,以便在性能上进行有意义的改进

更新:由于您访问位的范围,您可能可以从宏中挤出更多性能。例如,如果您需要访问四位,您可能会有如下宏:

#define GETBITS_0_4(x,in) (((in)[(x)/8] & 0x0f))
#define GETBITS_1_4(x,in) (((in)[(x)/8] & 0x1e) >> 1)
#define GETBITS_2_4(x,in) (((in)[(x)/8] & 0x3c) >> 2)
#define GETBITS_3_4(x,in) (((in)[(x)/8] & 0x78) >> 3)
#define GETBITS_4_4(x,in) (((in)[(x)/8] & 0xf0) >> 4)
#define GETBITS_5_4(x,in) ((((in)[(x)/8] & 0xe0) >> 5) | (((in)[(x)/8+1] & 0x01)) << 3)
#define GETBITS_6_4(x,in) ((((in)[(x)/8] & 0xc0) >> 6) | (((in)[(x)/8+1] & 0x03)) << 2)
#define GETBITS_7_4(x,in) ((((in)[(x)/8] & 0x80) >> 7) | (((in)[(x)/8+1] & 0x07)) << 1)
// ...etc
由于这是大量冗长的样板代码,特别是如果您有多个不同的宽度,您可能需要编写一个程序来生成所有
GETBIT.*
访问器函数


(我注意到,字节中的位是按我上面写的顺序存储的。如果需要的话,应用适当的变换来匹配结构)< /P> < P>因为问题是用C++标记的,有什么原因不能简单地使用标准?< /P> <代码>?定义GETBIT(x,in)((in))[((x)/ 8)]。&1以格雷格的解决方案为基础:

template<unsigned int n, unsigned int m> 
inline unsigned long getbits(unsigned long[] bits) {
  const unsigned bitsPerLong = sizeof(unsigned long) * CHAR_BIT
  const unsigned int bitsToGet = m - n;
  BOOST_STATIC_ASSERT(bitsToGet < bitsPerLong);
  const unsigned mask = (1UL << bitsToGet) - 1;
  const size_t index0 = n / bitsPerLong;
  const size_t index1 = m / bitsPerLong;
  // Do the bits to extract straddle a boundary?
  if (index0 == index1) {
    return (bits[index0] >> (n % bitsPerLong)) & mask;
  } else {
    return ((bits[index0] >> (n % bitsPerLong)) + (bits[index1] << (bitsPerLong - (m % bitsPerLong)))) & mask;
  }
}
模板
内联无符号长getbits(无符号长[]位){
const unsigned bitsPerLong=sizeof(unsigned long)*字符位
const unsigned int bitsToGet=m-n;
BOOST\u STATIC\u ASSERT(bitsToGet(n%bitsPerLong))&掩码;
}否则{

返回((位[index0]>>(n%bitsPerLong))+(位[index1]您可以使用
std::vector
而不是无符号字符数组和自定义宏。vector类模板对bool类型有一个特殊的模板专门化。提供此专门化是为了优化空间分配:在此模板专门化中,每个元素仅占用一位(比C++中最小的类型小八倍:char).

我经常访问-范围-位,从随机的非单词对齐m开始,以另一个随机的n结束。很好,这是一个很好的机会。我会在我的答案中添加更多内容。在这一点上,你希望模板诚实。请看我的答案。而KennyTM和MSalters提供了一些非常好的答案,这将是“正确的做法”如果我是一个人滚动整个系统,我必须处理来自外部来源的数据或在特定的“原始”环境中准备的数据要发送的格式和
std::bitset
不仅需要在这些区域上放置自定义分配器,而且对于位的内部布局,除了效率之外,什么都不能保证。在我的例子中,
位数组[n]
数据的内存布局是无法避免的。我知道每个字符的位数有些变化,但每个字符256位的数量很多。MSalters:谢谢,修复了。只有在可以在预定义的内存区域上分配数据的情况下。一个重要的是为屏幕生成一个库生成的位图。另外,它的性能更好吗?(嵌入式设备,资源有限,性能不足)@SF:您可能可以将std::bitset与使用内存映射位数组的自定义分配器一起使用。为什么您认为
std::bitset
特别慢?正如您正确指出的,在许多CPU上,访问单个位的速度并不快,但我看不出std::bitset增加开销的原因。事实上,它可以比
cha更快r[]
因为它可以消除混叠问题。+1到MSalters注释-std::bitset-启用了优化-不应该与宏有任何不同,只会减少出错的机会。但是,STL样式的代码在调试版本中可能会明显较慢-如果您注意到微秒的变化。+1这是正确的答案,尽管我不知道为什么poster认为
位集
比推出自己的要慢;
位集
在大多数系统上都是高度优化的我喜欢
((x)和7)
而不是
((x)%8)
,但我希望编译器无论如何都会使用这种优化。方括号在
定义中正确吗
#define GETBIT(x,in)   ((in)[ ((x)/8) ] & 1<<(7-((x)%8)))
#define GETBIT(x,in)   ((in)[ ((x) >>> 3) ] & 1<<((x) & 7))
template<unsigned int n, unsigned int m> 
inline unsigned long getbits(unsigned long[] bits) {
  const unsigned bitsPerLong = sizeof(unsigned long) * CHAR_BIT
  const unsigned int bitsToGet = m - n;
  BOOST_STATIC_ASSERT(bitsToGet < bitsPerLong);
  const unsigned mask = (1UL << bitsToGet) - 1;
  const size_t index0 = n / bitsPerLong;
  const size_t index1 = m / bitsPerLong;
  // Do the bits to extract straddle a boundary?
  if (index0 == index1) {
    return (bits[index0] >> (n % bitsPerLong)) & mask;
  } else {
    return ((bits[index0] >> (n % bitsPerLong)) + (bits[index1] << (bitsPerLong - (m % bitsPerLong)))) & mask;
  }
}