(X ^ 0x1)! = 0 nghĩa là gì?


183

Tôi đã xem qua đoạn mã sau

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

x ^ 0x1nghĩa là gì? Đây có phải là một số kỹ thuật tiêu chuẩn?


97
Mã obfuscation khá chuẩn.
raina77ow

47
Điều này có thể được giải quyết bằng cách tiếp cận tương tự như phương trình "bình thường": 0 != (x ^ 1)→ xor cả hai bên bằng 1 → (0 ^ 1) != (x ^ 1 ^ 1)→ đơn giản hóa →1 != x
Score_Under 19/12/13

4
Tôi không thấy if (1 != x)khó viết như thế nào .
Adriano Varoli Piazza

12
Ý kiến khác nhau, trước hết bởi @Spook, chỉ rõ ra rằng typecủa xkhông cho - do đó chúng tôi không biết đây là một số nguyên trong C ++ này tagged vấn đề. Chắc chắn, nếu đây là C hoặc xlà một số nguyên, câu trả lời là dễ, nhưng đó không phải là một số đã cho và khả năng quá tải operator ^tồn tại.
chux - Phục hồi Monica

11
Tôi không thấy làm thế nào điều này nhận được rất nhiều sự
ủng hộ

Câu trả lời:


277

Hoạt động XOR ( x ^ 0x1) đảo ngược bit 0. Vì vậy, biểu thức có nghĩa là: nếu bit 0 của x là 0 hoặc bất kỳ bit nào khác của x là 1, thì biểu thức là đúng.

Ngược lại biểu thức là sai nếu x == 1.

Vì vậy, bài kiểm tra giống như:

if (x != 1)

và do đó (được cho là) ​​bị xáo trộn không cần thiết.


39
Này, bạn không biết bối cảnh. Nếu x là một loại cờ bit nào đó, thì IMO thực sự rõ ràng hơn để viết nó như bây giờ hơn là sử dụng toán tử! =.
Spook

40
@Spook: mặc dù không chỉ kiểm tra một cờ bit đơn - nó đang kiểm tra toàn bộ chiều rộng của x. Nếu bạn chỉ muốn kiểm tra một bit thì có các thành ngữ rõ ràng hơn, chẳng hạn như sử dụng bit AND.
Paul R

115
Không cần thiết bị xáo trộn? Bạn không biết rằng đó là công việc của chúng tôi để làm xáo trộn mã. Nếu chúng ta viết mã đơn giản mà bất cứ ai cũng có thể hiểu, tại sao, nơi nào sẽ đi đến sự tôn nghiêm tôn giáo của các vị trí của chúng ta trên thế giới? Chúng tôi đột nhiên trở thành công nhân bình thường như mọi người khác. Obfuscation vốn là cần thiết.
Thơm

31
Thật ra Spook đã đúng. Phép thử (x! = 1) không tương đương. Mã có thể là C ++ (và trong C ++, ^ có thể là một toán tử làm bất cứ điều gì). Vì vậy, bạn không biết bối cảnh, @Spook là đúng.
xryl669

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

78
  • ^là hoạt động XOR bitwise
  • 0x11trong ký hiệu hex
  • x ^ 0x1sẽ đảo ngược bit cuối cùng x(tham khảo bảng chân lý XOR trong liên kết ở trên nếu điều đó không rõ ràng với bạn).

Vì vậy, điều kiện (0 != ( x ^ 0x1 ))sẽ đúng nếu xlớn hơn 1 hoặc nếu bit cuối cùng bằng x0. Chỉ để lại x == 1 là giá trị mà tại đó điều kiện sẽ sai. Vì vậy, nó tương đương với

if (x != 1)

PS địa ngục của một cách để thực hiện một điều kiện đơn giản như vậy, tôi có thể thêm. Đừng làm vậy. Và nếu bạn phải viết mã phức tạp, hãy để lại nhận xét . Em xin anh.


7
Không phải vậy x==0; 4 ^ 0x1là đúng, nhưng 4==0rõ ràng là sai.
Fred Foo

4
"điều kiện dường như bằng if (x == 0)", không bằng x != 1?
Andrew-Dufresne

6
Sự tương đương giả định đó xlà một loại tích phân. Nếu đó là một floathoặc double, thì tôi tin rằng biểu thức sẽ mang lại sự thật 1.0 <= x < 2.0. Và nếu xlà loại do người dùng xác định, biểu thức có thể trả về đúng nếu xlà Yugo, kangaroo, sinh nhật của nhà soạn nhạc nổi tiếng hoặc bất kỳ số nào chia sẻ ít nhất ba chữ số với giá trà bằng đô la hiện tại ở Trung Quốc.
supercat

4
@supercat Không có operator^cho float/ double.
fluffy

1
@supercat: Khi một chuyển đổi từ dấu phẩy động sang số nguyên được gọi, chuyển đổi sẽ ẩn (không yêu cầu cú pháp truyền). Nhưng không có chuyển đổi nào được kích hoạt bởi các toán tử bitwise, chúng chỉ đơn giản là thất bại đối với các loại dấu phẩy động.
Ben Voigt

49

Điều này có vẻ như là lời giải thích đơn giản, nhưng nếu ai đó muốn đi qua nó một cách chậm rãi thì nó nằm bên dưới:

^là một toán tử XOR bitwise trong c, c ++ và c #.

XOR bitwise lấy hai mẫu bit có độ dài bằng nhau và thực hiện thao tác OR độc quyền logic trên mỗi cặp bit tương ứng.

Độc quyền OR là một hoạt động logic xuất ra đúng bất cứ khi nào cả hai đầu vào khác nhau (một là đúng, một là sai).

Bảng chân lý của một xor b :

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

Vì vậy, hãy minh họa 0 == ( x ^ 0x1 )biểu thức ở cấp độ nhị phân:

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

vì thế:

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

34

Nó là toán tử OR (XOR) độc quyền. Để hiểu cách thức hoạt động, bạn có thể chạy mã đơn giản này

    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;

Đầu ra sẽ là

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

Vì vậy, biểu hiện này

0 != ( x ^ 0x1 )

sẽ chỉ đúng bằng nhau khi x! = 0x1.

Nó không thay đổi x chính nó. Nó chỉ kiểm tra xem x có bằng 0 hay 1. điều này có thể được thay đổi thành

if ( x != 0x1 )

19

Nó kiểm tra mà xthực sự là không 0x1... xoring xvới 0x1sẽ cho kết quả 0 chỉ khi x0x1... Đây là một thủ thuật cũ chủ yếu được sử dụng trong ngôn ngữ lắp ráp


Đây có phải là nhanh hơn != 1?
Fiddling Bits 19/12/13

2
vào thời cổ đại trong khi thực hiện tối ưu hóa lắp ráp thủ công (x86) nếu tôi nhớ chính xác thì xorcách tiếp cận chứa ít mã máy hơn và được thực thi nhanh hơn so với gán tương ứng cho 0... tuy nhiên câu hỏi này chứa xorAND so sánh, vì vậy tôi có thể nghĩ rằng đó !=có thể là nhanh hơn Tôi không chắc lắm, tuy nhiên, sẽ cần phải xem một số trình biên dịch được tạo.
Ferenc Deak 19/12/13

10
@BitFiddlingCodeMonkey: Không. Nếu XOR nhanh hơn một số bài kiểm tra đẳng thức gốc, trình biên dịch của bạn sẽ phát ra XOR để kiểm tra sự bằng nhau. Do đó, XOR không bao giờ nhanh hơn các bài kiểm tra công bằng về tối ưu hóa trình biên dịch. Quy tắc 101 của việc viết mã nhanh là "đừng thử và giúp trình biên dịch. Cuối cùng, bạn sẽ chỉ tạo ra mã không thể đọc được mà chậm hơn trong thực tế".
Matt

@fritzone IIRC, các thủ thuật XOR có liên quan nhiều hơn đến việc lưu các thanh ghi, lưu một tải đăng ký b / c nghĩa đen có thể được mã hóa trực tiếp trong OP trong một số trường hợp và một số khác biệt tinh tế với các cờ trạng thái (nhưng hầu hết sự lắp ráp của tôi đã được bật 68k và DSP).
mpdon Arena 19/12/13

1
@MPD: Thông thường phải làm với việc xóa một thanh ghi (ít nhất là trên 386+). xor eax, eax đặt eax về 0 trong hai byte, nhưng Mov eax, 0 mất ba hoặc sáu byte (tùy thuộc vào mã hóa) và mất một chút thời gian để giải mã hơn dạng xor .
Matt

18

Các ^nhà điều hành là Bitwise xor. Và 0x1là số 1, được viết dưới dạng hằng thập lục phân.

Vì vậy, x ^ 0x1đánh giá một giá trị mới giống như x, nhưng với bit ít quan trọng nhất được lật.

Mã không làm gì khác hơn là so sánh x với 1, theo cách rất phức tạp và tối nghĩa.


11

Toán tử xor (độc quyền hoặc) thường được sử dụng nhất để đảo ngược một hoặc nhiều bit. Hoạt động là hỏi chính xác một trong các bit có phải là một không, điều này dẫn đến bảng chân lý sau (A và B là đầu vào, Y là đầu ra):

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

Bây giờ mục đích của mã này dường như là để kiểm tra xem bit cuối cùng có phải là 1 hay không, và những cái khác là 0, điều này bằng if ( x != 1 ). Lý do cho phương pháp tối nghĩa này có thể là do các kỹ thuật thao tác bit trước đó đã được sử dụng và có lẽ được sử dụng ở những nơi khác trong chương trình.


8

^là bitwise xor operatorin c. Trong trường hợp của bạn x được xor'ed với 1. ví dụ xcó giá trị 10, 10d ^ 1d ===> 1010b ^ 0001b = 1011b, 1011b == 11ddo đó điều kiện trở thành đúng.


Typo trong câu trả lời của bạn. 10 != 1010
Fiddling Bits 19/12/13

@BitFiddlingCodeMonkey: lỗi đánh máy trong bình luận của bạn:10 (decimal) == 1010 (binary)
Paul R

6
@PaulR Làm thế nào để mọi người biết số thập phân và nhị phân là gì nếu bạn không đặt bhoặc một cái gì đó ở đó?
Fiddling Bits 19/12/13

0b1010 sẽ không phải là cách làm của Pythonic chứ?
TankorSmash

8

Thử nghiệm bitwise dường như là một sự xáo trộn có chủ ý, nhưng nếu dữ liệu cơ bản là dữ liệu của công ty từ hệ thống máy tính lớn của IBM thì có thể đơn giản là mã được viết để phản ánh tài liệu gốc. Các định dạng dữ liệu của IBM quay trở lại những năm 1960 và thường mã hóa các cờ thành các bit đơn lẻ trong một từ để lưu trữ. Khi các định dạng được sửa đổi, các byte cờ được thêm vào cuối các bản ghi hiện có để duy trì khả năng tương thích ngược. Ví dụ, tài liệu cho bản ghi SMF có thể hiển thị mã ngôn ngữ lắp ráp để kiểm tra ba bit riêng lẻ trong ba từ khác nhau trong một bản ghi để quyết định rằng dữ liệu là tệp đầu vào. Tôi biết rất ít về nội bộ TCP / IP, nhưng bạn cũng có thể tìm thấy các cờ bit ở đó.


7

Toán tử ^ là bitwise-xor (xem &, |). Kết quả cho một cặp bit là,

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

Vì vậy, biểu thức,

( x ^ 0x1 )

đảo ngược / lật bit thứ 0 của x (giữ nguyên các bit khác).

Xem xét liệu x có thể có các giá trị ngoài 0x0 và 0x1 không? Khi x là một trường bit đơn, nó chỉ có thể có các giá trị 0x0 và 0x1, nhưng khi x là một int (char / short / long / etc), các bit ngoài bit0 có thể ảnh hưởng đến kết quả của biểu thức.

Biểu thức như đã cho phép các bit bên cạnh bit0 ảnh hưởng đến kết quả,

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

Cái nào có tính trung thực tương đương như biểu thức này (đơn giản hơn),

if ( x ^ 0x1 )

Lưu ý rằng biểu thức này sẽ chỉ kiểm tra bit0,

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

Vì vậy, biểu thức như được trình bày là thực sự kết hợp hai kiểm tra biểu thức,

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

Có phải tác giả dự định chỉ kiểm tra bit0 và có nghĩa là sử dụng biểu thức này,

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

Hay tác giả có ý định đưa ra các giá trị cho bit1-bitN và xor của bit0?


7

Tôi đang thêm một câu trả lời mới bởi vì không ai thực sự giải thích làm thế nào để có được câu trả lời bằng trực giác.

Nghịch đảo +-.
Nghịch đảo ^^.

Làm thế nào để bạn giải quyết 0 != x - 1cho x? Bạn + 1sang hai bên: 0 + 1 != x - 1 + 11 != x.
Làm thế nào để bạn giải quyết 0 != x ^ 1cho x? Bạn ^ 1sang hai bên: 0 ^ 1 != x ^ 1 ^ 11 != x.


6

Tôi đoán rằng có các bit hoặc giá trị trường bit khác xvà điều này nhằm kiểm tra rằng chỉ có bit thứ tự thấp được đặt. Trong ngữ cảnh, tôi đoán rằng đây là mặc định và do đó mã hóa cái này và một số liên quanm (có thể tốn kém hơn để mã hóa) có thể được bỏ qua, bởi vì cả hai đều phải là giá trị mặc định, được khởi tạo trong một hàm tạo hoặc tương tự.

Bằng cách nào đó bộ giải mã phải có khả năng suy ra rằng các giá trị này bị thiếu. Nếu chúng ở cuối một số cấu trúc, nó có thể được truyền đạt thông qua một lengthgiá trị luôn luôn tồn tại.


4

XOR rất hữu ích trong cờ C # enum. Để xóa cờ đơn khỏi giá trị enum, cần sử dụng toán tử xor (tham khảo tại đây )

Thí dụ:

[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

NHƯNG câu hỏi là về C ++, không phải C #
theDmi 19/12/13

@theDmi: NHƯNG CSONG về thao tác bit và bitmask. Cờ enum trong C # chắc chắn là về bitmask.
Igrek.

Thêm vào đó, nó cũng có thể hữu ích trong C ++. Xem: Ngăn 1ngăn 2
Igrek.

Câu trả lời này dường như không liên quan gì đến câu hỏi ban đầu, ngoài một số thảo luận về toán tử XOR bitwise?
Paul R

4

Có rất nhiều câu trả lời hay nhưng tôi thích nghĩ về nó một cách đơn giản hơn.

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

Đầu tiên. Một câu lệnh if chỉ sai nếu đối số bằng không. Điều này có nghĩa là so sánh không bằng 0 là vô nghĩa.

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

Vì vậy, để lại cho chúng tôi:

if ( x ^ 0x1 );

Một XOR với một. Những gì XOR làm về cơ bản là phát hiện các bit khác nhau. Vì vậy, nếu tất cả các bit đều giống nhau, nó sẽ trả về 0. Vì 0 là sai, lần duy nhất nó sẽ trả về false là nếu tất cả các bit đều giống nhau. Vì vậy, sẽ là sai nếu các đối số là như nhau, đúng nếu chúng khác nhau ... giống như không bằng toán tử.

if ( x != 0x1 );

Nếu thực tế, sự khác biệt duy nhất giữa hai là !=sẽ trả về 0 hoặc 1, trong khi ^sẽ trả về bất kỳ số nào, nhưng tính trung thực của kết quả sẽ luôn giống nhau. Một cách dễ dàng để nghĩ về nó là.

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

"Đơn giản hóa" cuối cùng là chuyển đổi 0x1thành số thập phân là 1. Do đó, câu lệnh của bạn tương đương với:

if ( x != 1 )

1

^ là một XOR bitwise tử

Nếu x = 1

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

ở đây 0 == (x ^ 0x1)

Nếu x = 0

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

ở đây 0! = (x ^ 0x1)

Bảng chân lý của một xor b:

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

Mã đơn giản có nghĩa là


6
Có thực sự cần thiết để gửi một câu trả lời trùng lặp khác?
Bí ẩn

2
bạn có thể nói một câu trả lời khác nhưng không trùng lặp. xin lỗi nếu bạn phiền
akbar ali

1

Ở đây, kỹ thuật tiêu chuẩn thể được sử dụng là lặp lại một thành ngữ khi nó xuất hiện trong bối cảnh xung quanh cho rõ ràng, thay vì làm xáo trộn nó bằng cách thay thế nó bằng một thành ngữ đơn giản hơn về mặt ngữ cảnh nhưng vô nghĩa.

Các mã xung quanh có thể làm cho tham chiếu thường xuyên đến (x ^ 1) hoặc kiểm tra có thể hỏi "nếu bit 0 là cách khác, liệu mặt nạ bit này có trống không?".

Cho rằng điều kiện gây ra một cái gì đó là encode() ed, có thể trong bối cảnh, trạng thái mặc định của bit 0 đã bị đảo ngược bởi các yếu tố khác và chúng ta chỉ cần mã hóa thông tin bổ sung nếu bất kỳ bit nào lệch khỏi mặc định của chúng (thường là 0 ).

Nếu bạn lấy biểu thức ra khỏi ngữ cảnh và hỏi nó làm gì, bạn sẽ bỏ qua ý định tiềm ẩn. Bạn cũng có thể nhìn vào đầu ra lắp ráp từ trình biên dịch và thấy rằng nó chỉ đơn giản là thực hiện so sánh đẳng thức trực tiếp với 1.


0

Như tôi thấy các câu trả lời cho đến nay bỏ lỡ một quy tắc đơn giản để xử lý XORs. Không đi sâu vào chi tiết ý nghĩa ^0xý nghĩa (và if, !=v.v.), biểu thức 0 != (x^1)có thể được làm lại như sau bằng cách sử dụng thực tế rằng (a^a)==0:

0 != (x^1) <=> [xor left and right side by 1]
(0^1) != (x^1^1) <=>
1 != x
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.