手动更改 unsigned int 中的一组字节
Manually changing a group of bytes in an unsigned int
我正在使用 C 语言,我正在尝试弄清楚如何更改 32 位无符号整数中的一组位。
例如,如果我有
int a = 17212403u;
在二进制中,变成 1000001101010001111110011
。现在,假设我标记了这些位,它们以小端格式排列,最右边的位代表一个,右边第二个代表两个,依此类推,我如何手动更改一组位?
例如,假设我想更改位,使第 11 位到第 15 位的十进制值为 17,这怎么可能?
我正在考虑通过这样做来获得该范围:
unsigned int range = (a << (sizeof(a) * 8) - 14) >> (28)
但我不确定从现在开始该往哪里走。
第 11 位到第 15 位是 5 位,假设您的意思是包括第 15 位。 5 位是十六进制值:0x1f
然后你把这5位左移11位:0x1f << 11
现在我们有了要在原始变量中清除的位 11 到 15 的掩码,我们通过按位反转掩码和具有反转掩码的变量来做到这一点:a & ~(0x1f << 11)
下一步是将值 17 移到第 11 位:17 << 11
然后我们按位或将其放入我们清除的5位中:
unsigned int b = (a & ~(0x1f << 11)) | (17 << 11)
您将 (1) 首先必须清除位 11..15,然后 (2) 然后根据您要设置的值设置这些位。要实现 (1),请创建一个 "mask",将所有位设置为 1
,但要清除的位除外;然后使用 a & bitMask
将这些位设置为 0
。然后,使用 | myValue
将位设置为所需的值。
使用移位运算符 <<
将掩码和值放在正确的位置:
int main(int argc, char** argv) {
// Let's assume a range of 5 bits
unsigned int bitRange = 0x1Fu; // is ...00000000011111
// Let's assume to position the range from bit 11 onwards (i.e. move 10 left):
bitRange = bitRange << 10; // something like 000000111110000000000
unsigned int bitMask = ~bitRange; // something like 111111000001111111111
unsigned int valueToSet = (17u << 10); // corresponds to 000000101110000000000
unsigned int a = (17212403u & bitMask) | valueToSet;
return 0;
}
这是解释发生了什么的长版本。简而言之,您还可以这样写:
unsigned int a = (17212403u & ~(0x1Fu << 10)) | (17u << 10)
考虑使用位域。这允许您命名和访问整数的子部分,就好像它们是结构的整数成员一样。
有关 C 位域的信息,请参阅:
https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm
下面是使用位域执行您想要的操作的代码。该结构的 "middle5" 成员包含位 11-15。 "lower11" 成员是低 11 位的填充符,因此 "middle5" 成员将在正确的位置。
#include <stdio.h>
void showBits(unsigned int w)
{
unsigned int bit = 1<<31;
while (bit > 0)
{
printf("%d", ((bit & w) != 0)? 1 : 0);
bit >>= 1;
}
printf("\n");
}
int main(int argc, char* argv[])
{
struct aBitfield {
unsigned int lower11: 11;
unsigned int middle5: 5;
unsigned int upper16: 16;
};
union uintBits {
unsigned int whole;
struct aBitfield parts;
};
union uintBits b;
b.whole = 17212403u;
printf("Before:\n");
showBits(b.whole);
b.parts.middle5 = 17;
printf("After:\n");
showBits(b.whole);
}
程序输出:
Before:
00000001000001101010001111110011
After:
00000001000001101000101111110011
当然,您会希望为各个字段使用更有意义的命名。
不过请注意,位域在不同平台上的实现方式可能不同 - 因此它可能无法完全移植。
我正在使用 C 语言,我正在尝试弄清楚如何更改 32 位无符号整数中的一组位。
例如,如果我有
int a = 17212403u;
在二进制中,变成 1000001101010001111110011
。现在,假设我标记了这些位,它们以小端格式排列,最右边的位代表一个,右边第二个代表两个,依此类推,我如何手动更改一组位?
例如,假设我想更改位,使第 11 位到第 15 位的十进制值为 17,这怎么可能?
我正在考虑通过这样做来获得该范围:
unsigned int range = (a << (sizeof(a) * 8) - 14) >> (28)
但我不确定从现在开始该往哪里走。
第 11 位到第 15 位是 5 位,假设您的意思是包括第 15 位。 5 位是十六进制值:0x1f
然后你把这5位左移11位:0x1f << 11
现在我们有了要在原始变量中清除的位 11 到 15 的掩码,我们通过按位反转掩码和具有反转掩码的变量来做到这一点:a & ~(0x1f << 11)
下一步是将值 17 移到第 11 位:17 << 11
然后我们按位或将其放入我们清除的5位中:
unsigned int b = (a & ~(0x1f << 11)) | (17 << 11)
您将 (1) 首先必须清除位 11..15,然后 (2) 然后根据您要设置的值设置这些位。要实现 (1),请创建一个 "mask",将所有位设置为 1
,但要清除的位除外;然后使用 a & bitMask
将这些位设置为 0
。然后,使用 | myValue
将位设置为所需的值。
使用移位运算符 <<
将掩码和值放在正确的位置:
int main(int argc, char** argv) {
// Let's assume a range of 5 bits
unsigned int bitRange = 0x1Fu; // is ...00000000011111
// Let's assume to position the range from bit 11 onwards (i.e. move 10 left):
bitRange = bitRange << 10; // something like 000000111110000000000
unsigned int bitMask = ~bitRange; // something like 111111000001111111111
unsigned int valueToSet = (17u << 10); // corresponds to 000000101110000000000
unsigned int a = (17212403u & bitMask) | valueToSet;
return 0;
}
这是解释发生了什么的长版本。简而言之,您还可以这样写:
unsigned int a = (17212403u & ~(0x1Fu << 10)) | (17u << 10)
考虑使用位域。这允许您命名和访问整数的子部分,就好像它们是结构的整数成员一样。
有关 C 位域的信息,请参阅: https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm
下面是使用位域执行您想要的操作的代码。该结构的 "middle5" 成员包含位 11-15。 "lower11" 成员是低 11 位的填充符,因此 "middle5" 成员将在正确的位置。
#include <stdio.h>
void showBits(unsigned int w)
{
unsigned int bit = 1<<31;
while (bit > 0)
{
printf("%d", ((bit & w) != 0)? 1 : 0);
bit >>= 1;
}
printf("\n");
}
int main(int argc, char* argv[])
{
struct aBitfield {
unsigned int lower11: 11;
unsigned int middle5: 5;
unsigned int upper16: 16;
};
union uintBits {
unsigned int whole;
struct aBitfield parts;
};
union uintBits b;
b.whole = 17212403u;
printf("Before:\n");
showBits(b.whole);
b.parts.middle5 = 17;
printf("After:\n");
showBits(b.whole);
}
程序输出:
Before:
00000001000001101010001111110011
After:
00000001000001101000101111110011
当然,您会希望为各个字段使用更有意义的命名。
不过请注意,位域在不同平台上的实现方式可能不同 - 因此它可能无法完全移植。