第 10章 位 运 算
位运算是指对二进制位进行的运算。每个二进制位中
只能存放 0或 1。因此,位运算就是对二进制数的运算。通
常,将一个数据用二进制数表示后,最右边的二进制位称
为最低位(第 0位),最左边的二进制位为最高位。
图 10.1 微机中整数的二进制位表示
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
10.1 二进制位运算
10.2 位 段
10.3 程序举例
10.1 二进制位运算
在 C语言中共提供了 6种位运算符, 如表 10.1所示 。
表 10.1
位运算符 意 义
&
|
^
~
<<
>>
按位与
按位或
按位异或
按位取反
左移
右移
( 1) 在这 6种位运算符中, 其中按位取反是单目运算符,
只有一个运算对象, 其他均为双目运算符, 有两个运算对象 。
( 2) 位运算的运算对象只能是整型 ( 包括 int,short,
long和 unsigned) 或字符型数据, 而不能是实型数据 。
( 3) 各位运算符的优先级比较分散, 与其他运算符一起,
其优先级从高到低如下:
逻辑非 (!)?按位取反 (~)?算术运算符 ?左移运算符 (<<)
和右移运算符 (>>)?关系运算符 ?按位与运算符 (&),按位异
或运算符 (^),按位或运算符 (|)?&&与 ||?赋值运算符
1., 按位与, 运算符 (&)
“按位与, 的运算符为, &”。其运算规则是:若两个运算
对象的对应二进制位均是 1,则结果的对应位是 1,否则为 0。
利用, 按位与, 运算可以实现以下功能:
( 1) 取出数据中指定的位
( 2) 将数据中的指定位清零
2.“按位或”运算符( |)
,按位或, 的运算符为, |”。其运算规
则是:若两个运算对象的对应二进制位中
有一个是 1,则结果的对应位是 1,否则为 0
。
例 10.2 下列 C程序的功能是将整型数组中所有元素转换
为不小于它的最小奇数, 并显示输出 。。
#include "stdio.h"
main()
{ int k,a[10]= {23,14,24,31,46,55,33,68,27,40};
for (k= 0; k< 10; k++ )
printf("%5d",a[k]);
printf("\n");
for (k= 0; k< 10; k++ )
a[k]= a[k]|0x01;
for (k= 0; k< 10; k++ )
printf("%5d",a[k]);
printf("\n");
}
3., 按位异或, 运算符 (^)
“按位异或, 的运算符为, ^”。其运算规则是:若两个
运算对象的对应二进制位不相等,则结果的对应位是 1,否
则为 0。
,按位异或, 运算具有以下几个性质:
( 1) 使数据中的某些位取反, 即将 0变为 1,1变为 0。
( 2)同一个数据进行异或运算后,其结果为 0。利用异或
运算的这个性质,可以将变量清零。
( 3) 可以实现交换两个变量的值:
4.“按位取反”运算符 (~)
“按位取反, 的运算符为, ~”。其运算规则是:将运
算对象中的各二进制位值取反,即将 0变为 1,1变为 0。
5.“左移”运算符 (<<)
“左移”运算符为,<<”。其运算规则是:
将运算对象中的每个二进制位向左移动若干位
,从左边移出去的高位部分被丢弃,右边空出
的低位部分补 0。
6., 右移, 运算符 (>>)
“右移, 运算符为, >>”。 其运算规则是:将运算对象中
的每个二进制位向右移动若干位, 从右边移出去的低位部分
被丢弃 。 但左边空出的高位部分是补 0还是补 1,要视下列具
体情况而定:
若右移对象为无符号整型数, 则右移后左边空出的高位
部分补 0。
若右移对象为一般整型数或字符型数据,当该数据的最
高位为 0(对于一般整型来说即为正数),则右移后左边空
出的高位部分补 0。当该数据的最高位为 1(对于一般整型来
说即为正数),则与使用的计算机系统有关,有的计算机系
统将右移后左边空出的高位部分补 1,称为, 算术右移, ;
有的计算机系统将右移后左边空出的高位部分补 0,称为,
逻辑右移, 。
10.2 位 段
在 C语言中, 定义位段结构类型的一般形式为
struct 位段结构类型名
{ 成员表 };
在定义位段与使用位段时,要注意以下几个问题:
( 1)位段成员的类型必须是 unsigned型。
( 2)在位段结构类型中,可以定义无名位段,这种无
名位段具有位段之间的分隔作用。
( 3)每个位段(成员)所占的二进制位数一般不能超
过一个字长(即一个存储单元)。
( 4)在位段结构类型定义中,可以包含非位段成员。
( 5)位段可以在一般的表达式中被引用,并被自动转
换为相应的整数。
10.3 程序举例
例 10.3 编写一个 C程序,其功能是:从键盘输入一个
无符号整数 m以及位移位数 n,当 n> 0时,将 m循环右
移 n位;当 n< 0时,将 m循环左移 |n|位。
将一个无符号整数 m循环移 n位的方法如下:
首先用 sizeof函数确定一个无符号整数所占的二进制位数
k。
如果是循环右移,则先将 m右移 n位(即将原数的高 k-
n位移到低位),再将 m左移 k- n位(即将原数的低 n位移到
高位),然后将它们作按位或运算(即将它们合并)。
如果是循环左移,则先将 m左移 n位(即将原数的低 k-
n位移到高位),再将 m右移 k- n位(即将原数的高 n位移到
低位),然后将它们作按位或运算(即将它们合并)。
其 C程序如下:
#include "stdio.h"
main()
{ unsigned m;
int n;
printf("input m:");
scanf("%x",&m);
printf("input n:");
scanf("%d",&n);
if (n> 0)
printf("moveright= %x\n",moveright(m,n));
else
printf("moveleft= %x\n",moveleft(m,- n));
}
moveright(unsigned m,int n)
{ unsigned z;
int k;
k= 8*sizeof(unsigned);
z= (m>>n)|(m<<(k- n));
return(z);
}
moveleft(unsignedm,int n)
{ unsigned z;
int k;
k= 8*sizeof(unsigned);
z= (m<<n)|(m>>(k- n));
return(z);
}
位运算是指对二进制位进行的运算。每个二进制位中
只能存放 0或 1。因此,位运算就是对二进制数的运算。通
常,将一个数据用二进制数表示后,最右边的二进制位称
为最低位(第 0位),最左边的二进制位为最高位。
图 10.1 微机中整数的二进制位表示
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
10.1 二进制位运算
10.2 位 段
10.3 程序举例
10.1 二进制位运算
在 C语言中共提供了 6种位运算符, 如表 10.1所示 。
表 10.1
位运算符 意 义
&
|
^
~
<<
>>
按位与
按位或
按位异或
按位取反
左移
右移
( 1) 在这 6种位运算符中, 其中按位取反是单目运算符,
只有一个运算对象, 其他均为双目运算符, 有两个运算对象 。
( 2) 位运算的运算对象只能是整型 ( 包括 int,short,
long和 unsigned) 或字符型数据, 而不能是实型数据 。
( 3) 各位运算符的优先级比较分散, 与其他运算符一起,
其优先级从高到低如下:
逻辑非 (!)?按位取反 (~)?算术运算符 ?左移运算符 (<<)
和右移运算符 (>>)?关系运算符 ?按位与运算符 (&),按位异
或运算符 (^),按位或运算符 (|)?&&与 ||?赋值运算符
1., 按位与, 运算符 (&)
“按位与, 的运算符为, &”。其运算规则是:若两个运算
对象的对应二进制位均是 1,则结果的对应位是 1,否则为 0。
利用, 按位与, 运算可以实现以下功能:
( 1) 取出数据中指定的位
( 2) 将数据中的指定位清零
2.“按位或”运算符( |)
,按位或, 的运算符为, |”。其运算规
则是:若两个运算对象的对应二进制位中
有一个是 1,则结果的对应位是 1,否则为 0
。
例 10.2 下列 C程序的功能是将整型数组中所有元素转换
为不小于它的最小奇数, 并显示输出 。。
#include "stdio.h"
main()
{ int k,a[10]= {23,14,24,31,46,55,33,68,27,40};
for (k= 0; k< 10; k++ )
printf("%5d",a[k]);
printf("\n");
for (k= 0; k< 10; k++ )
a[k]= a[k]|0x01;
for (k= 0; k< 10; k++ )
printf("%5d",a[k]);
printf("\n");
}
3., 按位异或, 运算符 (^)
“按位异或, 的运算符为, ^”。其运算规则是:若两个
运算对象的对应二进制位不相等,则结果的对应位是 1,否
则为 0。
,按位异或, 运算具有以下几个性质:
( 1) 使数据中的某些位取反, 即将 0变为 1,1变为 0。
( 2)同一个数据进行异或运算后,其结果为 0。利用异或
运算的这个性质,可以将变量清零。
( 3) 可以实现交换两个变量的值:
4.“按位取反”运算符 (~)
“按位取反, 的运算符为, ~”。其运算规则是:将运
算对象中的各二进制位值取反,即将 0变为 1,1变为 0。
5.“左移”运算符 (<<)
“左移”运算符为,<<”。其运算规则是:
将运算对象中的每个二进制位向左移动若干位
,从左边移出去的高位部分被丢弃,右边空出
的低位部分补 0。
6., 右移, 运算符 (>>)
“右移, 运算符为, >>”。 其运算规则是:将运算对象中
的每个二进制位向右移动若干位, 从右边移出去的低位部分
被丢弃 。 但左边空出的高位部分是补 0还是补 1,要视下列具
体情况而定:
若右移对象为无符号整型数, 则右移后左边空出的高位
部分补 0。
若右移对象为一般整型数或字符型数据,当该数据的最
高位为 0(对于一般整型来说即为正数),则右移后左边空
出的高位部分补 0。当该数据的最高位为 1(对于一般整型来
说即为正数),则与使用的计算机系统有关,有的计算机系
统将右移后左边空出的高位部分补 1,称为, 算术右移, ;
有的计算机系统将右移后左边空出的高位部分补 0,称为,
逻辑右移, 。
10.2 位 段
在 C语言中, 定义位段结构类型的一般形式为
struct 位段结构类型名
{ 成员表 };
在定义位段与使用位段时,要注意以下几个问题:
( 1)位段成员的类型必须是 unsigned型。
( 2)在位段结构类型中,可以定义无名位段,这种无
名位段具有位段之间的分隔作用。
( 3)每个位段(成员)所占的二进制位数一般不能超
过一个字长(即一个存储单元)。
( 4)在位段结构类型定义中,可以包含非位段成员。
( 5)位段可以在一般的表达式中被引用,并被自动转
换为相应的整数。
10.3 程序举例
例 10.3 编写一个 C程序,其功能是:从键盘输入一个
无符号整数 m以及位移位数 n,当 n> 0时,将 m循环右
移 n位;当 n< 0时,将 m循环左移 |n|位。
将一个无符号整数 m循环移 n位的方法如下:
首先用 sizeof函数确定一个无符号整数所占的二进制位数
k。
如果是循环右移,则先将 m右移 n位(即将原数的高 k-
n位移到低位),再将 m左移 k- n位(即将原数的低 n位移到
高位),然后将它们作按位或运算(即将它们合并)。
如果是循环左移,则先将 m左移 n位(即将原数的低 k-
n位移到高位),再将 m右移 k- n位(即将原数的高 n位移到
低位),然后将它们作按位或运算(即将它们合并)。
其 C程序如下:
#include "stdio.h"
main()
{ unsigned m;
int n;
printf("input m:");
scanf("%x",&m);
printf("input n:");
scanf("%d",&n);
if (n> 0)
printf("moveright= %x\n",moveright(m,n));
else
printf("moveleft= %x\n",moveleft(m,- n));
}
moveright(unsigned m,int n)
{ unsigned z;
int k;
k= 8*sizeof(unsigned);
z= (m>>n)|(m<<(k- n));
return(z);
}
moveleft(unsignedm,int n)
{ unsigned z;
int k;
k= 8*sizeof(unsigned);
z= (m<<n)|(m>>(k- n));
return(z);
}