📄 logicalbitwise.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>逻辑运算、位元运算</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">C++ Gossip: 逻辑运算、位元运算</a></h1>
<br>
在逻辑上有所谓的“且”、“或”与“反”运算,在C++中也提供这几个基本逻辑运算所需的“逻辑运算子”(Logical
operator),分别为“且”(&&)、“或”(||)及“反相”(!)三个运算子。 <br>
<br>
来看看下面这个程式会输出什么? <br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">int
num = 75; </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">cout
<< (num > 70 && num
< 80) << endl; </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">cout
<< (num > 80 || num < 75) <<
endl; </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">cout
<< !(num > 80 || num < 75) <<
endl;</span><br>
</div>
<br>
三段程式分别会输出1、0与1,也就是分别表示true、false与true三种状况。 <br>
<br>
&&运算中,如果左边的式子已经被评断为false,则可立即判断整个式子为false,因而右边的式子就不会再评断;
|| 运算中如果左边的式子已经被评断为true,则可以判断整个式子为true,因而右边的式子就不会再评断。<br>
<br>
接下来看看“位元运算子”(Bitwise
operator),数位设计上有AND、OR、NOT、XOR与补数等运算,在C++中提供这些运算的就是位元运算子,它们的对应分别是AND
(&)、OR(|)、NOT(!)、XOR(^)与补数(~)。 <br>
<br>
如果您不会基本的位元运算,这边可以提供一个程式来显示各个运算的结果: <br>
<br>
<pre>#include <iostream><br>using namespace std;<br> <br>int main() { <br> cout << "AND运算:" << endl; <br> cout << "0 AND 0\t\t" << (0 & 0) << endl; <br> cout << "0 AND 1\t\t" << (0 & 1) << endl; <br> cout << "1 AND 0\t\t" << (1 & 0) << endl; <br> cout << "1 AND 1\t\t" << (1 & 1) << endl; <br><br> cout << "OR运算:" << endl; <br> cout << "0 OR 0\t\t" << (0 | 0) << endl; <br> cout << "0 OR 1\t\t" << (0 | 1) << endl; <br> cout << "1 OR 0\t\t" << (1 | 0) << endl; <br> cout << "1 OR 1\t\t" << (1 | 1) << endl; <br><br> cout << "XOR运算:" << endl; <br> cout << "0 XOR 0\t\t" << (0 ^ 0) << endl; <br> cout << "0 XOR 1\t\t" << (0 ^ 1) << endl; <br> cout << "1 XOR 0\t\t" << (1 ^ 0) << endl; <br> cout << "1 XOR 1\t\t" << (1 ^ 1) << endl; <br><br> cout << "NOT运算:" << endl; <br> cout << "NOT 0\t\t" << (!0) << endl; <br> cout << "NOT 1\t\t" << (!1) << endl; <br> <br> return 0;<br>}</pre>
<br>
执行结果如下: <br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">AND运算: <br>
0 AND 0 0 <br>
0 AND 1 0 <br>
1 AND 0 0 <br>
1 AND 1 1 <br>
OR运算: <br>
0 OR 0 0 <br>
0 OR 1 1 <br>
1 OR 0 1 <br>
1 OR 1 1 <br>
XOR运算: <br>
0 XOR 0 0 <br>
0 XOR 1 1 <br>
1 XOR 0 1 <br>
1 XOR 1 0 <br>
NOT运算: <br>
NOT 0 1 <br>
NOT 1 0<br>
</span></small></td>
</tr>
</tbody>
</table>
<br>
C++中的位元运算是逐位元运算的,例如10010001与01000001作AND运算,是一个一个位元对应运算,答案就是00000001;而补数运
算是将所有的位元0变1,1变0,例如00000001经补数运算就会变为11111110,例如下面这个程式所示: <br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">char num = 255; </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">cout
<< static_cast<int>(~num);</span><br>
</div>
<br>
这段程式会在主控台显示0,char使用一个位元组,若用于储存正整数最大可储存255的值,255的二进位表示法为11111111,经补数运算就是
00000000,也就是0。 <br>
<br>
要注意的是,逻辑运算子与位元运算子也是很常被混淆的,像是&&为逻辑运算,而&为位元运算,||为逻辑运算,而|为位元运算,
初学时可得多注意。 <br>
<br>
位元运算对初学者来说的确较不常用,但如果用的洽当的话,可以增进不少程式效率,例如下面这个程式可以判断使用者的输入是否为奇数:<br>
<br>
<pre>#include <iostream><br>using namespace std;<br><br>int main() { <br> int input = 0; <br><br> cout << "输入正整数:"; <br> cin >> input; <br> cout << "输入为奇数?" <br> << (input&1 ? 'Y' : 'N') <br> << endl; <br> <br> return 0;<br>}</pre>
<br>
执行结果如下: <br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">输入正整数:5<br>
输入为奇数?Y<br>
</span></small></td>
</tr>
</tbody>
</table>
<br>
这个程式得以运算的原理是,奇数的数值若以二进位来表示,其最右边的位元必为1,而偶数最右边的位元必为0,所以您使用1来与输入的值作AND运算,由于
1除了最右边的位元为1之外,其它位元都会是0,与输入数值AND运算的结果,只会留下最右边位元为0或为的结果,其它部份都被0
AND运算遮掉了,这就是所谓“位元遮罩”,例如:<br>
<table style="text-align: left; width: 25%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000100</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>4</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000001</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>1</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000000</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>判断为偶数</small></td>
</tr>
</tbody>
</table>
<br>
<br>
<table style="text-align: left; width: 25%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000011</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>3</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000001</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>1</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000001</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>判断为奇数</small></td>
</tr>
</tbody>
</table>
<br>
<br>
XOR的运算较不常见,这边举个简单的XOR字元加密例子,先看看程式:<br>
<br>
<pre>#include <iostream><br>using namespace std;<br> <br>int main() { <br> char ch = 'A'; <br><br> cout << "before encoding:" << ch <br> << endl; <br><br> ch = ch^0x7; <br> cout << "after encoding:" << ch <br> << endl; <br><br> ch = ch^0x7; <br> cout << "decoding:" << ch <br> << endl; <br> <br> return 0;<br>}</pre>
<br>
执行结果如下: <br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">before encoding:A<br>
after encoding:F<br>
decoding:A<br>
</span></small></td>
</tr>
</tbody>
</table>
<br>
0x7是C++中整数的16进位写法,其实就是10进位的7,将位元与1作XOR的作用其实就是位元反转,0x7的最右边三个位元为1,所以其实就是反转
ch的最后两个字元,如下所示:<br>
<table style="text-align: left; width: 273px;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>01000001</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace; width: 191px;"><small>65(对应
ASCII的'A')</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000111</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace; width: 191px;"><small>0x7</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>01000110</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace; width: 191px;"><small>70(对应
ASCII中的'F')</small></td>
</tr>
</tbody>
</table>
<br>
同样的,这个简单的XOR字元加密,要解密也只要再进行相同的位元反转就可以了。 <br>
<br>
要注意的是,虽然在说明时都只取8个位元来说明,但实际的位元在运算时,需依资料型态所占的记忆体长度而定,例如在使用int型态的0作运算时,要考虑的
是32个位元,而不是只有8个位元,因为int占有4个位元组。 <br>
<br>
在位元运算上,C++还有左移(<<)与右移(>>)两个运算子,注意在这边与cout与cin所使用的<<与
>>作用是不一样的;左移运算子会将所有的位元往左移指定的位数,左边被挤出去的位元会被丢弃,而右边会补上0;右移运算则是相反,会将所有
的位元往右移指定的位数,右边被挤出去的位元会被丢弃,至于左边位元补0或补1则不一定,视系统而定。 <br>
<br>
您可以使用左移运算来作简单的2次方运算示范,如下所示: <br>
<br>
<pre>#include <iostream><br>using namespace std;<br> <br>int main() { <br> int num = 1; <br><br> cout << "2的0次:" << num<br> << endl; <br><br> num = num << 1; <br> cout << "2的1次:" << num<br> << endl; <br><br> num = num << 1; <br> cout << "2的2次:" << num<br> << endl; <br><br> num = num << 1; <br> cout << "2的3次:" << num <br> << endl; <br> <br> return 0;<br>}</pre>
<br>
执行结果如下: <br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">2的0次:1<br>
2的1次:2<br>
2的2次:4<br>
2的3次:8<br>
</span></small></td>
</tr>
</tbody>
</table>
<br>
实际来左移看看就知道为何可以如此运算了: <br>
<table style="text-align: left; width: 25%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000001</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>1</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000010</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>2</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00000100</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>4</small></td>
</tr>
<tr>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>00001000</small></td>
<td style="font-weight: bold; font-family: Courier New,Courier,monospace;"><small>8</small></td>
</tr>
</tbody>
</table>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -