位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 字符串 1
s 和 0
s 而不是显示它。 p_start
是它应该从右边多少位开始(0
将是第一个变量中的最高有效位)。 p_length
是看多少位。之后,您可以根据需要传入任意多类型的不同变量。我没有让它检查 p_start
或 p_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
}
函数代码如下。 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;
}
假设我有 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 字符串 1
s 和 0
s 而不是显示它。 p_start
是它应该从右边多少位开始(0
将是第一个变量中的最高有效位)。 p_length
是看多少位。之后,您可以根据需要传入任意多类型的不同变量。我没有让它检查 p_start
或 p_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
}
函数代码如下。 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;
}