如何对内存块进行按位操作(C ++)

时间:2014-01-24 13:30:38

标签: c++ memory bit-manipulation bitwise-operators bitset

是否有比使用for循环更好(更快/更有效)的方法对大内存块执行按位操作?在查看选项之后,我注意到std有一个成员std::bitset,并且还想知道在不更改其值的情况下将大内存区域转换为bitset会更好(甚至可能),然后执行操作,然后将其类型切换回正常状态?

编辑/更新:我认为union可能适用于此处,以便为内存块分配new数组int或其他内容,然后将其作为大bitset进行操作}。根据这里所说的内容,似乎可以对整个集合进行操作:http://www.cplusplus.com/reference/bitset/bitset/operators/

1 个答案:

答案 0 :(得分:6)

一般来说,没有比for循环更快的神奇方法。但是,您可以通过记住以下几点来简化编译器优化循环:

  1. 一次将最大可用整数类型加载到内存中。但是,如果缓冲区的长度不能均匀分配整数类型的大小,则需要小心。
  2. 如果可能,在一次循环迭代中操作多个值 - 这应该使编译器的矢量化更加简单。同样,您需要注意缓冲区长度。
  3. 如果循环要在短代码段上运行多次,请使用向下计数到零而不是向上的循环索引,并从数组长度中减去它 - 这使得CPU的分支预测器更容易计算发生了什么事。
  4. 您可以使用编译器提供的显式向量扩展,但这会降低您的代码的可移植性。
  5. 最后,您可以在汇编中编写循环并使用CPU提供的向量指令,但这完全不可移植。
  6. [edit]此外,您可以使用OpenMP或类似的API在多个线程之间划分循环,但如果您在非常大的内存上执行操作,这只会带来改进。
  7. C99带有常量字节的xoring存储器示例,假设long long为128位,缓冲区的开始对齐为16个字节,而不考虑第3点。两个内存缓冲区上的按位运算非常相似。

    size_t len = ...;
    char *buffer = ...;
    
    size_t const loadd_per_i = 4
    size_t iters = len / sizeof(long long) / loads_per_i;
    
    long long *ptr = (long long *) buffer;
    long long xorvalue = 0x5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5eLL;
    
    // run in multiple threads if there are more than 4 MB to xor
    #pragma omp parallel for if(iters > 65536)
    for (size_t i = 0; i < iters; ++i) {
        size_t j = loads_per_i*i;
        ptr[j  ] ^= xorvalue;
        ptr[j+1] ^= xorvalue;
        ptr[j+2] ^= xorvalue;
        ptr[j+3] ^= xorvalue;
    }
    
    // finish long longs which don't align to 4
    for (size_t i = iters * loads_per_i; i < len / sizeof(long long); ++i) {
        ptr[i] ^= xorvalue;
    }
    
    // finish bytes which don't align to long
    for (size_t i = (len / sizeof(long long)) * sizeof(long long); i < len; ++i) {
        buffer[i] ^= xorvalue;
    }