(x ^ 0x1)!= 0是什么意思?


183

我遇到了以下代码片段

if( 0 != ( x ^ 0x1 ) )
     encode( x, m );

什么x ^ 0x1意思 这是一些标准技术吗?


97
代码混淆是相当标准的。
raina77ow 2013年

47
可以使用与“标准”方程式相同的方法来解决此问题:0 != (x ^ 1)→将两边加1或(0 ^ 1) != (x ^ 1 ^ 1)→简化→1 != x
Score_Under 2013年

4
我看不出有多if (1 != x)难写。
阿德里亚诺瓦里里广场

12
@Spook首先发表的各种评论清楚地指出,没有给出typeof x,因此我们不知道这是此C ++标记问题中的整数。当然,如果它是C或x整数,答案很简单,但这不是给定的,并且operator ^存在过载的可能性。
chux-恢复莫妮卡

11
我看不到如何获得如此多的投票...
laike9m 2013年

Answers:


277

XOR操作(x ^ 0x1)将位0反转。因此,该表达式有效地表示:如果x的位0为0,或者x的任何其他位为1,则该表达式为true。

相反,如果x == 1,则表达式为false。

因此测试与以下内容相同:

if (x != 1)

因此(毫无疑问)被不必要地混淆了。


39
嘿,你不知道上下文。如果x是某种位标志,则与使用!=运算符相比,IMO现在实际上更清楚地将其写入。
惊吓2013年

40
@Spook:不过,它不仅测试单个标志,而且还在测试x的整个宽度。如果只想测试一点,那么会有更清晰的习惯用法,例如使用按位与。
Paul R

115
不必要的混淆?您是否不知道混淆代码是我们的工作。如果我们编写任何人都可以理解的简单代码,那么为什么我们在世界上的地位所具有的宗教神圣性何处去?我们突然会像其他所有人一样成为普通工人。混淆本质上是必要的。
2013年

31
实际上,Spook是正确的。测试(x!= 1)不相等。代码可以是C ++(在C ++中,^可以是可以执行任何操作的运算符)。所以您不知道上下文,@ Spook是正确的。
xryl669 2013年

82
@TheThomуєтуσυωяιтєιи¢ℓєαятєχт–
bobobobo

78
  • ^是按位XOR运算
  • 0x11在16进制
  • x ^ 0x1会反转的最后一位x(如果不清楚,请参考上面链接中的XOR真值表)。

因此,(0 != ( x ^ 0x1 ))如果x大于1或条件的最后一位x为0,则条件为true。这仅使x == 1作为条件为false的值。所以这相当于

if (x != 1)

PS我可能会添加一种实现这种简单条件的方法。不要那样做 如果您必须编写复杂的代码,请发表评论。我请求您。


7
这不是x==0; 4 ^ 0x1是正确的,但4==0显然是错误的。
Fred Foo 2013年

4
“条件似乎等于if (x == 0)”,不是等于x != 1吗?
Andrew-Dufresne

6
等效条件x是整数。如果它是floator double,那么我相信该表达式将产生true 1.0 <= x < 2.0。并且如果x是用户定义的类型,则如果x是Yugo,袋鼠,著名作曲家的生日或任何与中国当前以美元计价的茶价格共享至少三位数的数字,则表达式可以返回true 。
2013年

4
@supercat没有operator^float/ double
蓬松的2013年

1
@supercat:当需要从浮点到整数的转换时,该转换是隐式的(不需要强制转换语法)。但是按位运算符不会触发任何转换,它们对于浮点类型只会失败。
Ben Voigt 2013年

49

这似乎是过于简单的解释,但是如果有人想慢慢地理解它,则如下所示:

^在c,c ++和c#中是按位XOR运算符。

按位XOR采用相等长度的两个位模式,并对每对对应位执行逻辑异或运算。

异或运算是一种逻辑运算,只要两个输入不同(一个为true,另一个为false),则输出true。

真值表一个XOR B

a           b        a xor b
----------------------------
1           1           0
1           0           1
0           1           1
0           0           0

因此,让我们0 == ( x ^ 0x1 )在二进制级别上说明该表达式:

             what? xxxxxxxx (8 bits)
               xor 00000001 (hex 0x1 or 0x01, decimal 1)    
             gives 00000000
---------------------------
the only answer is 00000001

所以:

   0 == ( x ^ 0x1 )    =>    x == 1
   0 != ( x ^ 0x1 )    =>    x != 1

34

它是异或(XOR)运算符。要了解其工作原理,您可以运行以下简单代码

    std::cout << "0x0 ^ 0x0 = " << ( 0x0 ^ 0x0 ) << std::endl;
    std::cout << "0x0 ^ 0x1 = " << ( 0x0 ^ 0x1 ) << std::endl;
    std::cout << "0x1 ^ 0x0 = " << ( 0x1 ^ 0x0 ) << std::endl;
    std::cout << "0x1 ^ 0x1 = " << ( 0x1 ^ 0x1 ) << std::endl;

输出将是

0x0 ^ 0x0 = 0
0x0 ^ 0x1 = 1
0x1 ^ 0x0 = 1
0x1 ^ 0x1 = 0

所以这个表达

0 != ( x ^ 0x1 )

仅当x!= 0x1时才等于true。

它不会改变x本身。它仅检查x等于0还是1。可以将rxpression更改为

if ( x != 0x1 )

19

它检查x实际上是不0x1... xor荷兰国际集团x0x1将导致0只要x0x1......这是大部分在汇编语言上使用的老把戏


比这快!= 1吗?
摆弄位

2
在远古时代,在做手工装配优化(86)如果我没有记错的xor方法包含较少的机器代码,并比相应的分配更快地执行0......但是这个问题包含xor和比较,所以我可能会认为!=可能是快点。但是我不确定,是否需要查看一些编译器生成的程序集。
Ferenc Deak 2013年

10
@BitFiddlingCodeMonkey:否。如果XOR比某些本机级相等性测试快,则​​编译器将发出XOR进行相等性测试。因此,XOR永远比优化编译器上的相等性测试快。编写快速代码的规则101是“不要尝试帮助编译器。您最终只会编写出在实践中较慢的不可读代码”。
马特

@fritzone IIRC,XOR技巧与保存寄存器有关,在某些情况下可以直接在OP中对文字进行编码,从而节省了寄存器加载b / c,并且与状态标志有一些细微的差异(但我的大部分汇编程序都在68k和DSP)。
mpdonadio

1
@MPD:通常与清除寄存器有关(至少在386+上)。xor eax,eax在两个字节中将eax设置为零,但是mov eax,0需要三或六个字节(取决于编码),并且解码所需的时间比xor形式稍长。
马特

18

^操作是按位异或运算。和0x1是数字1,用十六进制常量表示。

因此,x ^ 0x1求值的新值与相同x,但最低有效位被翻转。

该代码仅以复杂且模糊的方式将x与1进行比较。


11

xor(异或)运算符最常用于反转一个或多个位。该操作是询问位中的确切一位是否为1,这将导致以下真值表(A和B为输入,Y为输出):

A    B    Y
0    0    0
0    1    1
1    0    1
1    1    0

现在,此代码的目的似乎是检查最后一位是否为1,其他位是否为0(等于)if ( x != 1 )。这种晦涩的方法的原因可能是先前的位操作技术已被使用,并且可能在程序中的其他位置被使用。


8

^是按位xor operatorc。在您的情况下,x与1进行异或运算,例如x,其值为10,则10d ^ 1d ===> 1010b ^ 0001b = 1011b, 1011b == 11d条件变为true。


错别字。10 != 1010
摆弄位

@BitFiddlingCodeMonkey:您的注释中有错字:10 (decimal) == 1010 (binary)
Paul R

6
@PaulR如果您不在其中输入什么,那么应该如何知道小数和二进制b呢?
摆弄位

0b1010是不是Python的工作方式?
TankorSmash 2013年

8

按位测试似乎是故意的混淆,但是如果基础数据是来自IBM大型机系统的公司数据,则可能只是编写了代码以反映原始文档。IBM数据格式可以追溯到1960年代,经常将标志编码为一个字内的单个位,以节省存储空间。修改格式后,将标记字节添加到现有记录的末尾,以保持向后兼容性。例如,SMF记录的文档可能会显示汇编语言代码,以测试单个记录中三个不同单词中的三个独立位,从而确定该数据是输入文件。我对TCP / IP内部的了解很少,但是您也可能在那里找到位标志。


7

运算符^是按位异或(请参阅&,|)。一对位的结果是

0 ^ 0 == 0
0 ^ 1 == 1
1 ^ 0 == 1
1 ^ 1 == 0

所以表达

( x ^ 0x1 )

反转/翻转x的第0位(其他位保持不变)。

考虑x是否可以具有0x0和0x1以外的值?当x是单个位字段时,它只能具有值0x0和0x1,但是当x是int类型(char / short / long / etc)时,除bit0外的其他位都可以影响表达式的结果。

给出的表达式允许bit0旁边的位影响结果,

if ( 0 != ( x ^ 0x1 ) )

与这个(简单的)表达式具有同等的真实性,

if ( x ^ 0x1 )

请注意,此表达式仅检查bit0,

if( 0x1 & ( x ^ 0x1 ) )

因此,所提供的表达式实际上是结合了两个表达式检查,

if( ( x & ~0x1 )  //look at all bits besides bit0
||  ( x ^ 0x1 ) ) //combine with the xor expression for bit0

作者是否只打算检查bit0并打算使用此表达式,

if( 0x1 & ( x ^ 0x1 ) )

还是作者打算将bit1-bitN和bit0的xor值混合?


7

我要添加一个新答案,因为没有人真正解释过如何直观地获得答案。

的倒数+-
的倒数^^

你怎么解决0 != x - 1x?你+ 1给双方:0 + 1 != x - 1 + 11 != x
你怎么解决0 != x ^ 1x?你^ 1给双方:0 ^ 1 != x ^ 1 ^ 11 != x


6

我猜想中还有其他位或位字段值x,这是为了测试仅设置了低位。在上下文中,我猜这是默认值,因此m可以跳过对此和某些相关代码(可能更昂贵的编码)的编码,因为它们都必须都是默认值,必须在构造函数或类似方法中初始化。

解码器必须以某种方式能够推断出这些值丢失了。如果它们位于某个结构的末尾,则可以通过length始终存在的值进行通信。


4

XOR在C#标志枚举中很有用。要从枚举值中删除单个标志,必须使用xor运算符(在此处参考)

例:

[Flags]
enum FlagTest { None 0x0, Test1 0x1, Test2 0x2, Test3 0x4}

FlagTest test = FlagTest.Test2 | FlagTest.Test3;
Console.WriteLine(test); //Out: FlagTest.Test2 | FlagTest.Test3
test = test ^ FlagTest.Test2;
Console.WriteLine(test); //Out: FlagTest.Test3

但是问题是关于C ++而不是C#的
theDmi 2013年

@theDmi:还涉及位操作和位掩码。C#中的标志枚举肯定与位掩码有关。
伊格里克。

另外,它在C ++中也很有用。请参阅:堆栈1堆栈2
Igrek。

除了对按位XOR运算符的某些讨论以外,该答案似乎与原始问题没有任何关系。
Paul R

4

有很多好的答案,但我想以一种简单的方式来考虑。

if ( 0 != ( x ^ 0x1 ) );

首先。如果参数为零,则if语句仅是false。这意味着比较不等于零是没有意义的。

if ( a != 0 );
// Same as
if ( a );

这样就给我们留下了:

if ( x ^ 0x1 );

与一个异或。XOR所做的本质上是检测不同的位。因此,如果所有位都相同,则将返回0。由于0为假,因此,如果所有位都相同,则唯一返回false的时间。因此,如果参数相同,则为false;如果参数不同,则为true ...就像不等于运算符一样。

if ( x != 0x1 );

如果确实如此,则两者之间的唯一区别是!=将返回0或1,而^将返回任何数字,但是结果真实性始终相同。一个简单的思考方法是。

(b != c) === !!(b ^ c) // for all b and c

最终的“简化”将转换0x1为十进制的1。因此,您的语句等同于:

if ( x != 1 )

1

^是按位XOR运算符

如果x = 1

          00000001   (x)       (decimal 1)
          00000001   (0x1)     (decimal 1)
XOR       00000000   (0x0)     (decimal 0)

这里0 ==(x ^ 0x1)

如果x = 0

          00000000   (x)       (decimal 0)
          00000001   (0x1)     (decimal 1)
XOR       00000001   (0x1)     (decimal 0)

这里0!=(x ^ 0x1)

xor b的真值表:

a           b        a xor b
----------------------------
1           1           0
1           0           1
0           1           1
0           0           0

该代码只是意味着


6
是否真的有必要发布另一个重复的答案?
Mysticial

2
您可以说另一个答案,但不能重复。抱歉,如果您介意
akbar ali

1

可能的标准技术此处使用是,为了清晰起见,在周围的上下文中重复一个惯用语,而不是通过将其替换为在算术上更简单但在上下文上毫无意义的惯用语来对其进行混淆。

周围的代码可能经常引用(x ^ 1),或者测试可能会问“如果位0相反,该位掩码是否为空?”。

考虑到该条件导致某些问题encode(),可能是在上下文中,位0的默认状态已被其他因素反转,并且如果任何位偏离其默认值(通常为全零),我们仅需编码额外的信息)。

如果您使表达式脱离上下文而询问其作用,则您会忽略其潜在意图。您可能还需要查看编译器的程序集输出,并发现它只是与1进行了直接相等比较。


0

如我所见,到目前为止,答案中没有找到处理XORs 的简单规则。如果没有进入细节什么^0x均值(和if,和!=等),则表达式0 != (x^1)可以返工用事实如下(a^a)==0

0 != (x^1) <=> [xor left and right side by 1]
(0^1) != (x^1^1) <=>
1 != x
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.