15.0 位运算说明
位运算与其他一些底层运算在编写系统程序、加密程序、图像图形程序以及其他一些需要高执行速度或高效利用空间的程序时比较有用,但是由于某些位运算符与操作数是否有无符号有关,在编写普通的应用程序时并不建议使用。
注:本章内容基本都是复制了《C语言程序设计_现代方法(第2版)》的第20章-底层程序设计的相关内容。
15.1 移位运算
移位运算符可以向左或向右移动整数的二进制表示。C语言提供了两个移位运算符。
符号 | 含义 |
---|---|
<< | 左移位 |
>> | 右移位 |
运算符<<和>>的操作数可以是任意整数类型。对两个操作数都会进行整数提升,返回值的类型是左操作数提升后的类型。
i << j的值是将i中的位(的值)向左移动j位后的结果(的值)。向左移动一位的结果是:原最左端的位会移出,原最左端右边的各位都会左移一位,而最右端会补一个0。把i向左移动j位,可以理解为把i的值j次向左移动一位。
i >> j的值是将i中的位右移j位后的结果。向右移动一位的结果是:如果i是无符号数或非负值,需要在i的左端补0。如果i是负值,其结果是由实现定义的,一些实现会在左端补0,其他一些实现会保留符号位而补1。
为了可移植性,最好仅对无符号数进行移位运算。
下面演示对数19应用移位运算符的效果(简单起见,本章例子都使用16位的无符号短整型)
unsigned short i, j;
i = 19; // i的二进制是 0000000000010011 ,十进制是19
j = i << 1; // j的二进制是 0000000000100110 ,十进制是38
j = i << 2; // j的二进制是 0000000001001100 ,十进制是76
j = i >> 1; // j的二进制是 0000000000001001 ,十进制是9
j = i >> 2; // j的二进制是 0000000000000100 ,十进制是4
就像+运算符不会改变其操作数一样,两个移位运算符也都不会改变它的操作数(i的值不变)。如果需要修改i,需要把结果赋值给i,
i = 19; // i的二进制是 0000000000010011 ,十进制是19
i = i << 1; // i的二进制是 0000000000100110 ,十进制是38
i = i >> 1; // i的二进制是 0000000000010011 ,十进制是19
或者使用复合赋值运算符
i = 19; // i的二进制是 0000000000010011 ,十进制是19
i <<= 1; // i的二进制是 0000000000100110 ,十进制是38
i >>= 1; // i的二进制是 0000000000010011 ,十进制是19
其中,i <<= 1相当于i = i << 1,i >>= 1相当于i = i >> 1。
注意,移位运算符的优先级比算术运算符的优先级低,因此可能产生意料之外的结果。比如,i << 2 + 1等同于i << (2 + 1),而不是(i << 2) + 1。
15.2 按位求反、与、或、异或运算符
符号 | 含义 |
---|---|
~ | 按位求反 |
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
运算符~是一元运算符,对其操作数会进行整数提升。其他运算符都是二元运算符,对其操作数进行常用的算术转换。
运算符~、&、|和^对操作数的每一位执行布尔运算。~运算符会产生对操作数求反的结果,即将每一个0替换成1,将每一个1替换成0。运算符&对两个操作数对应的位执行逻辑与运算。运算符|和^相似,对两个操作数对应的位执行逻辑或运算。只是当两个操作数对应的位都是1时,^产生0。
下面的例子演示了这几个运算符,
unsigned short i, j, k;
i = 23; // i的二进制是0000000000010111 十进制是23
j = 53; // j的二进制是0000000000110101 十进制是53
k &#