了解 C 编程中的位操作 (set/clear)
Understanding bit manipulation (set/clear) in C programming
我无法理解 C 中整数的位运算。
假设我有数字 13。它的二进制表示是 1101
。如何将钻头设置在第二个位置?如何清除该位?
这是我目前为设置该位而编写的函数:
int setBit(int data, int pos, int val)
{
if (val==1)
data |= (1U << (pos - 1));
else
data ^= (1U << (pos-1));
return data;
}
这能正常工作吗?
n = n & (~(1U <<x))
将重置位置 x 的位。
实际上我们正在做的假设 n=1101
我们要重置第 3 位。
它是如何工作的?
所以 1U <<3=000....1000
~( 1U <<3)=111....0111
n=000..1101
& 111..0111
结果为 000..0101.
在位置x处插入一个位y:(位置从0开始)
1101---->11y01
给出位置2的例子。
num= FFFF FFFF (in hex)(all 1's) //1111......1111
number=N // in which you will insert bit
num1=num<<x; //for x=2 as in this case
//num1=1111.....1100
num2=~(num1); //num2=0000.....0011
lowbits=N & num2; // =0000.....0001 (N=1101)
highbits= N &num1;// =0000.....1100
highbits<<=1; // =0000....11000
N= highbits | lowbits;//=0000....11001
现在使用下面描述的方法根据需要设置第 x 位(此处 x=2)
注意:更一般地,可以通过这种方式将数字 n 的第 k 位更改为 y(可能是 0 或 1)
n^=(-y ^ n) & (1U <<k); (&- logical and)
位的删除与插入类似。一步步操作,你就搞定了。
编辑:我已将 1 的使用更改为 1U,因为在第一种情况下,仅使用 1 且不带任何修饰符被定义为有符号整数。从 K&R 开始,带符号值的右移是实现定义的。此外,如果您左移一个带符号的数字以影响符号位,则结果是未定义的。
These operations on unsigned value have well define behaviour: Vacated fields are filled with zeroes.
设置、清除和切换位的状态非常简单:
inline void bit_set (unsigned long *bf, unsigned char n)
{ *bf |= (1 << n); }
inline void bit_clear (unsigned long *bf, unsigned char n)
{ *bf &= ~(1 << n); }
inline void bit_toggle (unsigned long *bf, unsigned char n)
{ *bf ^= (1 << n); }
注意: 位域和上述函数是基于零的(即最低有效位是 bit 0
不是bit 1
) 因此,如果您想清除、设置或切换从右数起的第二位(bit index 1
、2's bit (binary)
或 bit 2
从右到左计数),你传递了一个bit index of 1
。上面函数中的n
就是bit index
。以下是快速参考:
+-----+-----+-----+-----+-----+-----+-----+-----+
bit index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
binary | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
+-----+-----+-----+-----+-----+-----+-----+-----+
这是一个使用 bit 1
操作的简单示例,(二进制中的 2 位):
#include <stdio.h>
#include <stdlib.h>
#define WDSZ 64
/* bit functions */
inline void bit_set (unsigned long *bf, unsigned char n) { *bf |= (1 << n); }
inline void bit_clear (unsigned long *bf, unsigned char n) { *bf &= ~(1 << n); }
inline void bit_toggle (unsigned long *bf, unsigned char n) { *bf ^= (1 << n); }
/* simple return of binary string */
char *binstr (unsigned long n);
int main (int argc, char **argv) {
unsigned long bf = (argc > 1) ? strtoul (argv[1], NULL, 10) : 13;
printf ("\n original value : %3lu (%s)\n", bf, binstr (bf));
bit_set (&bf, 1);
printf (" set bit 1 : %3lu (%s)\n", bf, binstr (bf));
bit_clear (&bf, 1);
printf (" clear bit 1 : %3lu (%s)\n", bf, binstr (bf));
bit_toggle (&bf, 1);
printf (" toggle bit 1 : %3lu (%s)\n\n", bf, binstr (bf));
return 0;
}
/* simple return of binary string */
char *binstr (unsigned long n) {
static char s[WDSZ + 1] = {0};
char *p = s + WDSZ;
while (n) {
p--;
*p = (n & 1) ? '1' : '0';
n >>= 1;
}
return p;
}
输出
$ ./bin/bitsetcleartoggle
original value : 13 (1101)
set bit 1 : 15 (1111)
clear bit 1 : 13 (1101)
toggle bit 1 : 15 (1111)
每当我遇到这样的问题时,我都会把它分解成更小的部分...
suppose i have no 13 binary of 13 is 1101
now how can i add extra bit at second position?
好的,这很简单...首先让一个数字在第二个位置有一个位,其他地方都是零...为了方便我们将使用一个 int...
int mask = 2; // or 0x2 if you rather or 0b10 if your compiler supports that ...
嗯,这不是很特别,我不能像以前那样重复使用那台机器……所以让我们尝试不同的方式……
int mask = 1 << 1; // 1 in the fist position moved one to the left...
好的,现在我们有了一部分,现在有 2 种直观的方法可以在我们的 13...
int answer = 13 | mask; // binary OR
或
int answer = 13 + mask;
这 2 个对于 13 是相同的...但是对于 14 会给出不同的答案...因为 +
总是添加值,而 |
只会更改不存在的位'设置在左侧...所以您需要选择适合您的语义...
现在你的第二个问题有点棘手...首先我们将选择相同的面具...
//pick nth bit
int mask = 1 < n;
// now to toggle that on a number... XOR
int answer = q ^ mask;
我喜欢使用第 n 个 vs 位置,因为它在 0 的情况下更有意义...
//For Inserting Bit
int insertbit(int data,int pos,int val)
{
int no1,no2;
no1=data;
no1=no1>>(pos-1);
no1=no1<<(pos-1);
no2=data-no1;
no1=no1<<1;
no1=no1 | no2;
if(val==1)
{
no1=setbit(no1,pos,val);
}
return no1;
}
//Setting Bits
int setbit(int data,int pos,int val)
{
int no=1;
no=no<<(pos-1);
if(val==0)
{
no=~no;
data=data&no;
}
else
{
data=no|data;
}
return data;
}
我是这样编码的,但是我需要一些代码插入功能的快捷方式
根据我的理解,您的问题是:
int setBit(int data, int pos, int val) {
if (val)
return data | (1U << (pos - 1));
else
return data & ~(1U << (pos - 1));
}
但我认为从 1
开始对位进行编号不是一个好主意。更常见的用法是对从0
到sizeof(type) * CHAR_BIT - 1
的位进行编号
我无法理解 C 中整数的位运算。
假设我有数字 13。它的二进制表示是 1101
。如何将钻头设置在第二个位置?如何清除该位?
这是我目前为设置该位而编写的函数:
int setBit(int data, int pos, int val)
{
if (val==1)
data |= (1U << (pos - 1));
else
data ^= (1U << (pos-1));
return data;
}
这能正常工作吗?
n = n & (~(1U <<x))
将重置位置 x 的位。
实际上我们正在做的假设 n=1101
我们要重置第 3 位。
它是如何工作的?
所以 1U <<3=000....1000
~( 1U <<3)=111....0111
n=000..1101
& 111..0111
结果为 000..0101.
在位置x处插入一个位y:(位置从0开始)
1101---->11y01 给出位置2的例子。
num= FFFF FFFF (in hex)(all 1's) //1111......1111
number=N // in which you will insert bit
num1=num<<x; //for x=2 as in this case
//num1=1111.....1100
num2=~(num1); //num2=0000.....0011
lowbits=N & num2; // =0000.....0001 (N=1101)
highbits= N &num1;// =0000.....1100
highbits<<=1; // =0000....11000
N= highbits | lowbits;//=0000....11001
现在使用下面描述的方法根据需要设置第 x 位(此处 x=2)
注意:更一般地,可以通过这种方式将数字 n 的第 k 位更改为 y(可能是 0 或 1)
n^=(-y ^ n) & (1U <<k); (&- logical and)
位的删除与插入类似。一步步操作,你就搞定了。
编辑:我已将 1 的使用更改为 1U,因为在第一种情况下,仅使用 1 且不带任何修饰符被定义为有符号整数。从 K&R 开始,带符号值的右移是实现定义的。此外,如果您左移一个带符号的数字以影响符号位,则结果是未定义的。
These operations on unsigned value have well define behaviour: Vacated fields are filled with zeroes.
设置、清除和切换位的状态非常简单:
inline void bit_set (unsigned long *bf, unsigned char n)
{ *bf |= (1 << n); }
inline void bit_clear (unsigned long *bf, unsigned char n)
{ *bf &= ~(1 << n); }
inline void bit_toggle (unsigned long *bf, unsigned char n)
{ *bf ^= (1 << n); }
注意: 位域和上述函数是基于零的(即最低有效位是 bit 0
不是bit 1
) 因此,如果您想清除、设置或切换从右数起的第二位(bit index 1
、2's bit (binary)
或 bit 2
从右到左计数),你传递了一个bit index of 1
。上面函数中的n
就是bit index
。以下是快速参考:
+-----+-----+-----+-----+-----+-----+-----+-----+
bit index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
binary | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
+-----+-----+-----+-----+-----+-----+-----+-----+
这是一个使用 bit 1
操作的简单示例,(二进制中的 2 位):
#include <stdio.h>
#include <stdlib.h>
#define WDSZ 64
/* bit functions */
inline void bit_set (unsigned long *bf, unsigned char n) { *bf |= (1 << n); }
inline void bit_clear (unsigned long *bf, unsigned char n) { *bf &= ~(1 << n); }
inline void bit_toggle (unsigned long *bf, unsigned char n) { *bf ^= (1 << n); }
/* simple return of binary string */
char *binstr (unsigned long n);
int main (int argc, char **argv) {
unsigned long bf = (argc > 1) ? strtoul (argv[1], NULL, 10) : 13;
printf ("\n original value : %3lu (%s)\n", bf, binstr (bf));
bit_set (&bf, 1);
printf (" set bit 1 : %3lu (%s)\n", bf, binstr (bf));
bit_clear (&bf, 1);
printf (" clear bit 1 : %3lu (%s)\n", bf, binstr (bf));
bit_toggle (&bf, 1);
printf (" toggle bit 1 : %3lu (%s)\n\n", bf, binstr (bf));
return 0;
}
/* simple return of binary string */
char *binstr (unsigned long n) {
static char s[WDSZ + 1] = {0};
char *p = s + WDSZ;
while (n) {
p--;
*p = (n & 1) ? '1' : '0';
n >>= 1;
}
return p;
}
输出
$ ./bin/bitsetcleartoggle
original value : 13 (1101)
set bit 1 : 15 (1111)
clear bit 1 : 13 (1101)
toggle bit 1 : 15 (1111)
每当我遇到这样的问题时,我都会把它分解成更小的部分...
suppose i have no 13 binary of 13 is 1101
now how can i add extra bit at second position?
好的,这很简单...首先让一个数字在第二个位置有一个位,其他地方都是零...为了方便我们将使用一个 int...
int mask = 2; // or 0x2 if you rather or 0b10 if your compiler supports that ...
嗯,这不是很特别,我不能像以前那样重复使用那台机器……所以让我们尝试不同的方式……
int mask = 1 << 1; // 1 in the fist position moved one to the left...
好的,现在我们有了一部分,现在有 2 种直观的方法可以在我们的 13...
int answer = 13 | mask; // binary OR
或
int answer = 13 + mask;
这 2 个对于 13 是相同的...但是对于 14 会给出不同的答案...因为 +
总是添加值,而 |
只会更改不存在的位'设置在左侧...所以您需要选择适合您的语义...
现在你的第二个问题有点棘手...首先我们将选择相同的面具...
//pick nth bit
int mask = 1 < n;
// now to toggle that on a number... XOR
int answer = q ^ mask;
我喜欢使用第 n 个 vs 位置,因为它在 0 的情况下更有意义...
//For Inserting Bit
int insertbit(int data,int pos,int val)
{
int no1,no2;
no1=data;
no1=no1>>(pos-1);
no1=no1<<(pos-1);
no2=data-no1;
no1=no1<<1;
no1=no1 | no2;
if(val==1)
{
no1=setbit(no1,pos,val);
}
return no1;
}
//Setting Bits
int setbit(int data,int pos,int val)
{
int no=1;
no=no<<(pos-1);
if(val==0)
{
no=~no;
data=data&no;
}
else
{
data=no|data;
}
return data;
}
我是这样编码的,但是我需要一些代码插入功能的快捷方式
根据我的理解,您的问题是:
int setBit(int data, int pos, int val) {
if (val)
return data | (1U << (pos - 1));
else
return data & ~(1U << (pos - 1));
}
但我认为从 1
开始对位进行编号不是一个好主意。更常见的用法是对从0
到sizeof(type) * CHAR_BIT - 1