我在进行位操作时,有些困惑何时使用异或运算符。按位与和按位或都很简单。当你想要屏蔽某些位时,使用按位与(常见用例是IP地址和子网掩码)。当你想要打开某些位时,使用包含或。然而,异或总是让我感到困惑,如果在面试中被问及需要使用异或的问题,我永远不会理解。有人能解释一下何时使用它以及一些常见用例吗?
我在进行位操作时,有些困惑何时使用异或运算符。按位与和按位或都很简单。当你想要屏蔽某些位时,使用按位与(常见用例是IP地址和子网掩码)。当你想要打开某些位时,使用包含或。然而,异或总是让我感到困惑,如果在面试中被问及需要使用异或的问题,我永远不会理解。有人能解释一下何时使用它以及一些常见用例吗?
0x0A ^ 0xFF = 0x03 ( 00001010 ^ 11111111 = 11110101 )
交换数字:
operation example
A B
initial: 0011 1010
a = a^b; 1001 1010
b = a^b; 1001 0011
a = a^b; 1010 0011
如您所见,这里的数字(在此情况下是四位二进制数)A和B被交换而没有使用额外的空间。这适用于相同类型的任何两个数字(尽管在C语言中,按位运算符需要无符号整数)
XOR操作也可用于“弱加密”。您可以将一个字符串与(重复的)“密码词”进行XOR运算,结果将是一串毫无意义的字节。再次应用相同的操作,原始字符串会出现。这是一种非常薄弱的算法,不应在现实生活中使用。
关于切换位 - 在“旧时代”,如果您想要反转图像,则需要为每个像素执行 pix = pix & 1
- 或者如果您可以每次以字节为单位执行,则为byte = byte & 0xFF
。这将把黑色文本在白色背景上变成白色文本在黑色背景上。我认为ATARI有一个专利,可以通过使用位图和XOR来创建“屏幕上任何位置”的闪烁光标。
同样,如果您有一个微控制器希望创建闪烁的光,重复执行state = state XOR 1
将导致状态切换。
最后,有许多“位操作技巧”依赖于XOR操作。例如,可以使用以下方法(源自:http://graphics.stanford.edu/~seander/bithacks.html)计算字的奇偶性(即设置位数是奇数还是偶数):
unsigned int v; // word value to compute the parity of
v ^= v >> 16;
v ^= v >> 8;
v ^= v >> 4;
v &= 0xf;
return (0x6996 >> v) & 1;
还有许多其他的“聪明技巧” - 它们通常会在你试图找到涉及位操作的最快方法时出现。大多数人可以毫不费力地度过一生,而不必真正“理解”它,这很好。我喜欢位操作。
除了其他答案中解释的按位交换两个数字和位切换外,XOR
操作还用于在不使用 if
语句的情况下找到两个数字的最大值。
int max(int x, int y)
{
return x ^ ((x ^ y) & -(x < y));
}
if
语句。现在已经更正了。 - haccks#define MAX(a,b) ((a)>(b))?(a):(b)
更快吗? - Floris在创意方面,XOR操作通常用于根据给定点的当前X和Y坐标呈现简单的正方形图形。例如,类似于棋盘的图案,具有可变的单元格大小:
#include <stdio.h>
#define CELLSIZE 2 /* cell size is actually 2 power CELLSIZE */
#define MASK (1<<CELLSIZE)
int main()
{
int i,j;
for (i=0;i<32;i++)
{
for (j=0;j<32;j++)
putchar (' '+('*'-' ')*( ((i&MASK)^(j&MASK))!=0 ) );
putchar ('\n');
}
return 0;
}
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
**** **** **** ****
我最喜欢的一个例子是原地交换。(注意:这是C++代码,而不是C代码,但你可以理解。)
void swap(int &x, int &y)
{
x ^= y;
y ^= x;
x ^= y;
}
n
是第n位,在b
中被切换)a = b ^ (1 << n)
x
和y
指向同一个对象,则会失败。只需使用临时变量即可。如果要交换的对象非常大,而您无法承担分配临时变量的成本,请使用循环逐个交换字节或字。 - Keith Thompsonx
和y
不能指向同一个对象,它们都是整数。除非你这样调用swap(x, x)
,这什么也不做。 :) - Keelerx
和y
不是指针,它们是语法错误。(该问题标记为C,而不是C++。) - Keith ThompsonXOR 的一个应用可以在特定情况下看到,当给定一个数组,其中每个数字都重复出现,除了一个不重复的单一数字需要被找到时。对所有数字进行 XOR 运算将得到仅出现一次的数字。
int arr[]={1, 1, 2, 2, 3, 3, 4};
// frequency of every number in the array is 2 except one number.
int sz=7; //size of array
int x=0;
for(int i=0;i<sz;i++)
x^=arr[i];
// x would give the number 4 here