位窗口操作

时间:2015-11-22 19:11:41

标签: c++ bit-manipulation

假设我有2个64位无符号整数。我有一个大小为110......的窗口,它一次从第一个整数的末尾开始,到第二个整数的开头结束。 (当然,我知道它从哪里开始)

例如,第一个是0,第二个是10,窗口从第一个0110011 110开始,窗口大小为0110011 and 110....... 。输出应为{{1}}。

我的问题是,如何编写这样一个体面的程序来解决这个问题?我尝试使用掩码,然后意识到我有2个块位整数({{1}}),我不知道如何将它们连接在一起。

2 个答案:

答案 0 :(得分:1)

试试这个:

#include <stdio.h>
int main() {
    unsigned long long i1 = 0x0123456789ABCDEFULL;
    unsigned long long i2 = 0x11223344AABBCCDDULL;

    // window start 7, size 12 bits
    // so it should include bits 7..0 from i1 and 63..60 from i2
    int windowStart =  7; // bit 7 of i1
    int windowSize  = 12;

    // Number of most significant bits needed from i2
    int numBitsFromSecondNum = windowSize - windowStart - 1;
    // AND mask of i1 to obtain the least significant bits from it
    unsigned long long chunk1 = i1 & ((1 << (windowStart+1)) - 1);
    // Right shift i2 to obtain the most significant bits from it
    unsigned long long chunk2 = i2 >> (64 - numBitsFromSecondNum);

    // Concatenation of the 2 chunks
    unsigned long long result = (chunk1 << numBitsFromSecondNum) | chunk2; 

    printf("%llX\n", chunk1); // prints: EF
    printf("%llX\n", chunk2); // prints: 1
    printf("%llX\n", result); // prints: EF1

    return 0;
}

窗口的开始和大小不在您的问题中,但我选择它们与4位对齐,以便轻松查看以十六进制打印的输出。

在上面的代码中,我假设unsigned long long(与unsigned long long int相同)大小为64位。 C标准保证它至少为64位,这意味着它可能更大(例如128位)。最好用(8*sizeof(unsigned long long))替换。

答案 1 :(得分:0)

这有点过于复杂,但它可以以更长的时间为代价提供更大的灵活性。

功能签名是:

template <typename... Ts_>
std::string see_bit_range(std::size_t p_start, std::size_t p_length, const Ts_&... p_types)

它创建并返回10 s的字符串,而不是显示它。 p_start是它应该从右边开始的位数(0将是第一个变量中最重要的位)。 p_length是要看多少位。之后,您可以根据需要传入尽可能多的不同类型的变量。我没有检查p_startp_length是否太大,或者如果你将零参数传递给它,那么就不要这样做。

取两个变量:unsigned char var1 = 0b00110011, var 2 = 0b11000000;。调用类似see_bit_range(1, 10, var1, var2)的函数,结果是字符串&#34; 0110011 110&#34;。

int main()
{
    const uint64_t var1 = 0b0110011; //...0110011
    const uint64_t var2 = 3ull << 62; //110...
    const int start = 57; //How many bits from the left to start at (64 - 7)
    const int length = 10; //How many bits to read

    std::cout << see_bit_range(start, length, var1, var2); //0110011 110
}

Like this.

功能代码如下。 get_var_sum是计算所有对象大小的辅助工具,否则不重要。它可以完全通过使用new分配的内存而不是像我那样使用本地数组来省略。

#include <string> //string
#include <cstddef> //size_t
#include <climits> //CHAR_BIT

template <typename T_, typename... Ts_>
struct get_var_sum
{
    static constexpr std::size_t value = sizeof(T_) + get_var_sum<Ts_...>::value;
};

template <typename T_>
struct get_var_sum<T_>
{
    static constexpr std::size_t value = sizeof(T_);
};

template <typename... Ts_>
std::string see_bit_range(std::size_t p_start, std::size_t p_length, const Ts_&... p_types)
{
    std::string out; //The string that represents the bits

    constexpr std::size_t SIZE_SUM = get_var_sum<Ts_...>::value; //The size of all the types combined
    unsigned char buffer[SIZE_SUM]; //A buffer to store the binary values in
    constexpr std::size_t ELEMENTS = sizeof...(Ts_); //The number of elements

    const unsigned char* ptrs[ELEMENTS]{ reinterpret_cast<const unsigned char*>(&p_types)... }; //Creates an array of pointers to the objects
    std::size_t sizes[ELEMENTS]{ sizeof(Ts_)... }; //Creates an array that holds the sizes of the objects

    out.reserve(CHAR_BIT * SIZE_SUM); //Be nice and tell the string what to expect

    bool small_endian; //If we're on a small endian or big endian machine
    unsigned long long test = 1;
    small_endian = *reinterpret_cast<unsigned char*>(&test) == 1;

    std::size_t x, y, z = 0;
    for (x = 0; x < ELEMENTS; ++x) //For each value
    {
        for (y = 0; y < sizes[x]; ++y) //For each byte in the value
            buffer[z++] = ptrs[x][small_endian ? sizes[x] - y - 1 : y]; //Copy the value into the buffer
    }
    y = 0;
    z = 0;
    for (x = p_start; x < p_start + p_length; ++x) //For the bit range specified
    {
        if ((x - y) / CHAR_BIT == sizes[z]) //If we just reached the end of a variable
        {
            y = x;
            ++z;
            out.push_back(' '); //Put a space in the string
        }
        out.push_back(((buffer[x / CHAR_BIT] & (1u << (CHAR_BIT - (x % CHAR_BIT) - 1))) > 0) ? '1' : '0'); //Show if the bit is on or not
    }
    return out;
}