相关文章推荐
朝气蓬勃的伤疤  ·  SQL Server ...·  1 年前    · 
曾经爱过的小笼包  ·  MatLab 自编的 ...·  1 年前    · 
严肃的香菇  ·  streamlit google ...·  1 年前    · 

位操作符一般用在数值类型上,它作用在数字二进制格式的每一位上(0和1),所以我们先要搞清楚十进制和二进制的相互转换。这篇文章开头我会给出一些(二进制-十进制)转换示例,虽然都是以Byte类型进行说明的,但其他诸如Int32、Int16等数值类型转换的原理是一样的。

位操作符的使用不仅仅只在C#和VB.NET两种语言中,本篇文章只以这两种语言举例。

“二进制 - 十进制”相互转换

这一节中我将介绍有关十进制与二进制相互转换的内容。

十进制-> 二进制

假设我们有一个十进制数字783,我们可以使用下面的方法将其转换成二进制:

  • 然后加1得到:1111110011110001
  • 那么,-783的二进制为1111110011110001
  • 怎么确定得到的结果是一个负数呢?这主要依赖于数据类型。如果数据类型为Int16,那么第一位若为0,则为正数,否则为负数。如果数据类型是不带符号的,比如UInt16,那么第一位数不代表符号,1111110011110000就是十进制的64752。
  • 二进制-> 十进制

    如果你有一个二进制数字0000000100010110(Int16),现将每个位的顺序颠倒(你会得到0110100010000000),然后使用以下方法:

    如果两个数是Int16类型的,那么它们就有可能是负数。一个负数和一个正数按位或运算后得到的结果还是负数(第一位肯定是1),因此,-15|378(VB.NET中-15 Or 378)的结果为-5。

    C#和VB.NET中的按位或运算符的使用,参见下面代码:

    [VB.NET]

    FlagsAttribute

    通过使用FlagsAttribute,你可以将枚举类型的每个值都当作二进制中的位(1和0),当然在定义枚举类型的时候有要求,即每个枚举值必须按照1、2、4、8(2的N次方)这样的规律初始化。

    [VB.NET]

    现在你可以使用按位或运算符来操作枚举类型:

    [VB.NET]

    AND 运算符(按位与 &

    假设有两个数76和231,我们现将它们转换成二进制:

    然后按照下表计算:

    仅仅当A和B都为负时,A&B(VB.NET中的A And B)的结果才为负,其他情况下结果都为正(只有A和B的第一位都为1时,结果的第一位才为1)。

    C#和VB.NET中的按位与运算符的使用,参见下图:

    [VB.NET]

    XOR 运算符(按位异或 ^

    XOR 运算符的工作方式

    按位或OR运算符不同于按位异或XOR运算符。如果你使用按位或OR,那么1|1(VB.NET中的1 Or 1)的结果为1,但是如果你使用按位异或XOR,那么1^1(VB.NET中的1 Xor 1)的结果为0。仅仅在1^0或者0^1时,结果才为1。

    假设你有两个数值138和43,那么现将它们转换为二进制格式:

    然后按照下表:

    使用XOR 加密

    在XOR运算符的帮助下,你可以给一个文本加密。遍历文本的每个字符,然后使用XOR运算符c ^ k(VB.NET中的c Xor k)生成新的字符。其中k就是一个整数值。

    [VB.NET]

    最终输出结果为zFG]♫G]♫O♫CK]]OIK。这种方式加密非常容易被破解,所以最好不要使用单一的字符(比如k),我们可以使用一串文本:

    [VB.NET]

    最终的输出为m_☻\ D+♫.↓Z♫\SL?Ka。现在破解这个加密算法相对来讲要复杂一些,但是这种方式还不是很保险,如果别人知道了你的key(代码中的k字符串),那么破解起来相当简单。因此,不要使用XOR这种方式作为加密的单一算法,如果你对安全、加密感兴趣,你可以结合其他的一些加密方式,将XOR运算符应用到其中,作为整个加密过程的一部分。

    NOT 运算符(按位非 ~

    按位非操作符NOT将会改变二进制中每位的值,0变为1,1变为0。如果一个数值有符号,那么整数经过运算后会变成负数,负数经过变换后会变为正数。如果数值没有符号,那么永远都为正(0除外)。假设你有一个数值52(二进制00110100,Byte类型,无符号),那么~52(VB.NET中的Not 52)的计算方式为:

    x>>n表示将x的二进制格式的每位均向右移动n个位置,左边空出来的位置补0(与左移相反)。

    如上图所示,每位均向右移动1个位置。所以155>>1的值为77。注意如果为负数,那么它的符号会被隐藏掉。

    下表显示的是计算155>>n的值:

    循环按位左移会将数值的二进制格式中的每位均向左移动1个位置,然后将移出来的数值(1或0)替补到右边空白处。

    上图显示了将154循环按位向左移动1位,它的值等于154<<1|154>>7。循环按位左移得到的结果可以归纳为:a<<n|a>>(b-n)。b为数值的位数,如果数值为Byte类型,那么最后的结果为a<<n|a>>(8-n),如果数值为Int32类型,那么b为32,最后的结果为a<<n|a>>(32-n)。

    C#和VB.NET中循环按位左移的使用,可以参见下面:

    [VB.NET]

    循环按位右移

    循环按位右移会将数值的二进制格式的每位均向右移动1个位置,然后将移出来的数值(1或0)替补到左边空白处。

    如上图所示,将155循环按位右移1个位置,最后它的值等于155>>1|155<<7。循环按位右移得到的结果可以归纳为:a>>n|a<<(b-n)。其中b为数值位数。如果数值为Byte类型,那么结果为a>>n|a<<(8-n),如果数值为Int32类型,那么得到的结果为a>>n|a<<(32-n)。

    C#和VB.NET中循环按位右移的使用,可以参见下面代码:

    [VB.NET]

    译者注:在使用位操作符时,一定要先确定被操作的数值是什么类型,占多少位,同一个数值,数据类型不同,最后得到的结果不一样。原文中,对于任何一个数值(比如52),都在强调它是Byte类型还是Int16类型。