“按位右移”的版本间的差异

来自Microduino Wikipedia
跳转至: 导航搜索
(Created page with "*'''Bitwise AND (&), Bitwise OR (|), Bitwise XOR (^)''' 按位与(&) 按位操作符对变量进行位级别的计算。它们能解决很多常见的编程问题。下...")
 
第1行: 第1行:
*'''Bitwise AND (&), Bitwise OR (|), Bitwise XOR (^)'''
+
*'''bitshift left (<<), bitshift right (>>)'''
按位与(&)
+
*'''描述'''
  
按位操作符对变量进行位级别的计算。它们能解决很多常见的编程问题。下面的材料大多来自这个非常棒的按位运算指导。
+
出自Playground的 The Bitmath Tutorial 在C++语言中有两个移位运算符:
  
说明和语法
+
左移位运算符(«)和右移运算符(»)。这些操作符可使左运算元中的某些位移动右运算元中指定的位数。
  
下面是所有的运算符的说明和语法。进一步的详细资料,可参考教程。
+
*'''语法'''
 +
<pre style="color:green">
  
按位与(&)
+
variable « number_of_bits variable » number_of_bits
 +
</pre>
  
位操作符与在C + +中是一个&符,用在两个整型变量之间。按位与运算符对两侧的变量的每一位都进行运算,规则是:如果两个运算元都是1,则结果为1,否则输出0.另一种表达方式:
+
*'''参数'''
 +
<pre style="color:green">
  
0 0 1 1 运算元1
+
variable - (byte, int, long) number_of_bits integer ⇐ 32
0 1 0 1 运算元2
 
----------
 
0 0 0 1(运算元1&运算元2)-返回结果
 
在Arduino中,int类型为16位,所以在两个int表达式之间使用&会进行16个并行按位与计算。代码片段就像这样:
 
<pre style="color:green">
 
    int a =  92;    //二进制: 0000000001011100
 
    int b = 101;    // 二进制: 0000000001100101
 
    int c = a & b;  // 结果:    0000000001000100, 或10进制的68
 
 
</pre>
 
</pre>
  
a和b的16位每位都进行按位与计算,计算结果存在c中,二进制结果是01000100,十进制结果是68.
+
*'''例子'''
 +
<pre style="color:green">
  
按位与最常见的作用是从整型变量中选取特定的位,也就是屏蔽。见下方的例子。
+
    int a = 5;        // 二进制数: 0000000000000101
 +
    int b = a << 3;  // 二进制数: 0000000000101000, 或十进制数:40
 +
    int c = b >> 3;  // 二进制数: 0000000000000101, 或者说回到开始时的5
 +
</pre>
  
按位或(|)
+
当你将x左移y位时(x«y),x中最左边的y位会逐个逐个的丢失:
 +
<pre style="color:green">
  
按位或操作符在C++中是|。和&操作符类似,|操作符对两个变量的为一位都进行运算,只是运算规则不同。按位或规则:只要两个位有一个为1则结果为1,否则为0。换句话说:
+
    int a = 5;        // 二进制: 0000000000000101
 +
    int b = a << 14;  // 二进制: 0100000000000000 - 101中最左边的1被丢弃
 +
如果你确定位移不会引起数据溢出,你可以简单的把左移运算当做对左运算元进行2的右运算元次方的操作。例如,要产生2的次方,可使用下面的方式:
 +
<pre style="color:green">
  
0 0 1 1 运算元1
+
1 << 0 == 1
0 1 0 1 运算元2
+
1 << 1 == 2
----------
+
1 << 2 == 4
0 1 1 1(运算元1 | 运算元2) - 返回的结果
+
1 << 3 == 8
这里是一个按位或运算在C + +代码片段:
+
...
<pre style="color:green">
+
1 << 8 == 256
    int a = 92;    // 二进制: 0000000001011100
+
1 << 9 == 512
    int b = 101;    //二进制: 0000000001100101
+
10 << 1 == 1024
    int c = a | b;  // 结果:    0000000001111101, 或十进制的125
+
...
 
</pre>
 
</pre>
  
示例程序
+
当你将x右移y位(x»y),如果x最高位是1,位移结果将取决于x的数据类型。如果x是int类型,最高位为符号位,确定是否x是负数或不是,正如我们上面的讨论。如果x类型为int,则最高位是符号位,正如我们以前讨论过,符号位表示x是正还是负。在这种情况下,由于深奥的历史原因,符号位被复制到较低位:
 +
<pre style="color:green">
  
按位与和按位或运算常用于端口的读取-修改-写入。在微控制器中,一个端口是一个8位数字,它用于表示引脚状态。对端口进行写入能同时操作所有引脚。
+
X = -16; //二进制:1111111111110000
 +
Y = X >> 3 //二进制:1111111111111110
 +
</pre>
  
PORTD是一个内置的常数,是指0,1,2,3,4,5,6,7数字引脚的输出状态。如果某一位为1,着对应管脚为HIGH。(此引脚需要先用pinMode()命令设置为输出)因此如果我们这样写,PORTD=B00110001;则引脚2、3、7状态为HIGH。这里有个小陷阱,我们可能同时更改了引脚0、1的状态,引脚0、1是Arduino串行通信端口,因此我们可能会干扰通信。
+
这种结果,被称为符号扩展,往往不是你想要的行为。你可能希望左边被移入的数是0。右移操作对无符号整型来说会有不同结果,你可以通过数据强制转换改变从左边移入的数据:
 +
<pre style="color:green">
  
我们的算法的程序是:
+
X = -16; //二进制:1111111111110000
 +
int y = (unsigned int)x >> 3;  // 二进制: 0001111111111110
 +
</pre>
  
读取PORT并用按位与清除我们想要控制的引脚
+
如果你能小心的避免符号扩展问题,你可以将右移操作当做对数据除2运算。例如:
 
 
用按位或对PORTD和新的值进行运算
 
 
<pre style="color:green">
 
<pre style="color:green">
int i;    // 计数器
 
int j;
 
 
void setup()
 
DDRD = DDRD | B11111100; //设置引脚2~7的方向,0、1脚不变(xx|00==xx)
 
//效果和pinMode(pin,OUTPUT)设置2~7脚为输出一样
 
serial.begin(9600);
 
}
 
 
void loop ()  {
 
for (i=0; i<64; i++){
 
 
PORTD = PORTD & B00000011;  // 清除2~7位,0、1保持不变(xx & 11 == xx)
 
j = (i << 2);              //将变量左移为·2~7脚,避免0、1脚
 
PORTD = PORTD | j;          //将新状态和原端口状态结合以控制LED脚
 
Serial.println(PORTD, BIN); // 输出掩盖以便调试
 
delay(100);
 
}
 
}
 
</pre>
 
 
按位异或(^)
 
  
C++中有一个不常见的操作符叫按位异或,也叫做XOR(通常读作”eks-or“)。按位异或操作符用‘^'表示。此操作符和按位或(|)很相似,区别是如果两个位都为1则结果为0:
+
INT = 1000;
 
+
Y = X >> 3; 8 1000 //1000整除8,使y=125
0 0 1 1 运算元1
 
0 1 0 1 运算元2
 
----------
 
0 1 1 0(运算元1 ^运算元2) - 返回的结果
 
按位异或的另一种解释是如果两个位值相同则结果为0,否则为1。
 
 
 
下面是一个简单的代码示例:
 
<pre style="color:green">
 
    int x = 12;     // 二进制: 1100
 
    int y = 10;    // 二进制: 1010
 
    int z = x ^ y;  // 二进制: 0110, 或十进制 6
 
// Blink_Pin_5
 
//演示“异或”
 
void setup(){
 
DDRD = DDRD | B00100000; //设置数字脚5设置为输出
 
serial.begin(9600);
 
}
 
 
void loop ()  {
 
PORTD = PORTD ^ B00100000;  // 反转第5位(数字脚5),其他保持不变
 
delay(100);
 
}
 
 
</pre>
 
</pre>
 
  
 
[[https://www.microduino.cn/wiki/index.php/Arduino_%E8%AF%AD%E6%B3%95%E6%89%8B%E5%86%8C/zh 返回Arduino语法手册]]
 
[[https://www.microduino.cn/wiki/index.php/Arduino_%E8%AF%AD%E6%B3%95%E6%89%8B%E5%86%8C/zh 返回Arduino语法手册]]

2016年3月28日 (一) 09:27的版本

  • bitshift left (<<), bitshift right (>>)
  • 描述

出自Playground的 The Bitmath Tutorial 在C++语言中有两个移位运算符:

左移位运算符(«)和右移运算符(»)。这些操作符可使左运算元中的某些位移动右运算元中指定的位数。

  • 语法

variable « number_of_bits variable » number_of_bits
  • 参数

variable - (byte, int, long) number_of_bits integer ⇐ 32
  • 例子

    int a = 5;        // 二进制数: 0000000000000101
    int b = a << 3;   // 二进制数: 0000000000101000, 或十进制数:40
    int c = b >> 3;   // 二进制数: 0000000000000101, 或者说回到开始时的5

当你将x左移y位时(x«y),x中最左边的y位会逐个逐个的丢失:


    int a = 5;        // 二进制: 0000000000000101
    int b = a << 14;  // 二进制: 0100000000000000 - 101中最左边的1被丢弃
如果你确定位移不会引起数据溢出,你可以简单的把左移运算当做对左运算元进行2的右运算元次方的操作。例如,要产生2的次方,可使用下面的方式:
<pre style="color:green">

1 << 0 == 1
1 << 1 == 2
1 << 2 == 4
1 << 3 == 8
...
1 << 8 == 256
1 << 9 == 512
10 << 1 == 1024
...

当你将x右移y位(x»y),如果x最高位是1,位移结果将取决于x的数据类型。如果x是int类型,最高位为符号位,确定是否x是负数或不是,正如我们上面的讨论。如果x类型为int,则最高位是符号位,正如我们以前讨论过,符号位表示x是正还是负。在这种情况下,由于深奥的历史原因,符号位被复制到较低位:


X = -16; //二进制:1111111111110000
Y = X >> 3 //二进制:1111111111111110

这种结果,被称为符号扩展,往往不是你想要的行为。你可能希望左边被移入的数是0。右移操作对无符号整型来说会有不同结果,你可以通过数据强制转换改变从左边移入的数据:


X = -16; //二进制:1111111111110000
int y = (unsigned int)x >> 3;  // 二进制: 0001111111111110

如果你能小心的避免符号扩展问题,你可以将右移操作当做对数据除2运算。例如:


INT = 1000;
Y = X >> 3; 8 1000  //1000整除8,使y=125

[返回Arduino语法手册]