位window操作

Bit window operation

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

比如第一个是...0110011,第二个是110......,而window是从第一个0开始,[= =24=] 是 10。输出应该是 0110011 110.

我的问题是,如何写出这么好的程序来解决这个问题?我尝试使用掩码,然后意识到我得到了 2 个块位整数 (0110011 and 110.......),但我不知道如何将它们连接在一起。

试试这个:

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

Window start 和 size 与你的问题不同,但我选择它们对齐到 4 位,以便轻松查看以十六进制打印的输出。

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

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

函数签名是:

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

它创建 returns 字符串 1s 和 0s 而不是显示它。 p_start 是它应该从右边多少位开始(0 将是第一个变量中的最高有效位)。 p_length是看多少位。之后,您可以根据需要传入任意多类型的不同变量。我没有让它检查 p_startp_length 是否太大,或者如果你向它传递零参数,所以不要那样做。

像这样取两个变量:unsigned char var1 = 0b00110011, var 2 = 0b11000000;。像see_bit_range(1, 10, var1, var2)这样调用函数,结果是字符串“0110011 110”。

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