第十章 位运算
★ 内容提要:
位逻辑运算
移位运算
复合位运算
位段
? 位逻辑运算
? 移位运算
? 复合位运算
? 位段
位运算是指对操作数以二进制位( bit ) 为
单位进行数据加工。 C 语言的位运算功能有:
? 位逻辑运算(四种);
? 位移操作(两种)。
参加位操作的操作数必须是整型常量或 变量。
一、位逻辑运算,
位 逻 辑 运 算 种 类
运算符 名 称 例 子 功 能
~
位反 ~ b 求 b 的位反
& 位与 b & c 求 b 和 c 的位与
| 位或 b | c 求 b 和 c 的位或
^
位异或 b ^ c 求 b 和 c 的位异或
名 称 例 子 功 能
求
求 和
求 和
求 和
名 称名 称 例 子例 子 功 能功 能
求求
求 和求 和
求 和求 和
求 和求 和
1,位反运算
位反运算是单项运算,它是把一个操作数按
位求反,即操作数的各个二进制位为 1 时变换
为 0,为 0 时变换成 1 。
例 [10-1]:将变量 a按位求反赋予变量 b。
void main(){
unsigned char a,b;
a=0x9a; b=~a;
printf("a:0x%x b:0x%x\n",a,b);
}
void main(){
unsigned char a,b;
a=0x9a; b=~a;
printf("a:0x%x b:0x%x \ n",a,b);
}
1 0 0 1 1 0 1 0a
运行结果:
a:0x9a b:0x65
0 1 1 0 0 1 0 1b
b= ~a
2,位与、位或和位异或是对两个操作数的对
应二进制位进行运算。
a 位 b 位
a &b
位与
a|b
位或
a^b
位异或
1
1
0
0
1
0
1
0
1
0
0
0
1
1
1
0
0
1
1
0
位 位位位 位位
位 逻 辑 运 算 种 类
例 [10 - 2],位逻辑运算。
void main(){
unsigned char a,b;
a=0xb9;
b=0x83;
printf("a and b:0x%x \ n",a&b);
printf("a and b:0x%x \ n",a|b);
printf("a and b:0x%x \ n",a^b);
}
运行结果:
a and b:0x81
a and b:0xbb
a and b:0x3a
1 0 1 1 1 0 0 1 a,0x b9
1 0 0 0 0 0 1 1 b,0x 83a&b
1 0 0 0 0 0 0 1 结果, 0 x 81
1 0 1 1 1 0 0 1 a,0 x b 9
1 0 0 0 0 0 1 1 b,0 x 8 3a | b
1 0 1 1 1 0 1 1 结果, 0 x b b结果
0 0 1 1 1 0 1 0 结果, 0 x 3a
1 0 1 1 1 0 0 1 a,0x b9
1 0 0 0 0 0 1 1 b,0x 83a^ b
注意:
对一个操作数的位运算并不改变操作
数本身的数值 。
二、移位操作
移位操作是对操作数以二进制位( bit ) 为
单位进行左移或右移。它们是双目运算符。
形式,〈操作数〉移位运算符〈移动的 位 数〉
运 算 种 类
运算符
名称 例子 运算功能
>> 右移位 b>>3 b 右移 3 位
<< 左移位 c<<2 b 左移 2 位
位
位
位位
位位
例 [10 - 3],左移位操作。
void main(){
unsigned char a,b;
a=0x1b; b=a<<2;
printf("0x%x left_shift 2 bit:0x%x \ n",a,b);
}
运行结果:
0 x1b left_shift 2 bit:0x6c
0 0 0 1 1 0 1 1 a,0x 1b
0 1 1 0 1 1 0 0 b,0x 6c
舍弃
补零
b=a< <2
说明:
1) 左移位操作中,操作数移位后,右端出现
的空格补 0,而移至左端之外的位舍去,不
管其是否为符号位。
0 0 0 1 1 0 1 1 a,0x 1b
0 1 1 0 1 1 0 0 b,0x 6c
舍弃
补零
b=a< <2
说明:
2) 每向左移一位,相当于该数乘 2 。
3) 右移位操作与操作数的数据类型是否带有
符号有关:
0 0 0 1 1 0 1 1 a,0x 1b
0 1 1 0 1 1 0 0 b,0x 6c
舍弃
补零
b=a< <2
? 不带符号的操作数右移位时,左端出现的空
位补零。
? 带符号的操作数右移位时,左端出现的空位
按原最左端的位复制,无论什么操作数,移
出右端的位被舍弃。
0 0 0 1 1 0 1 1 a,0x 1b
0 1 1 0 1 1 0 0 b,0x 6c
舍弃
补零
b=a< <2
例 [10 - 4],右移位操作。
void main(){
char a= - 8; uns igned char b=248;
printf("s igned a right_shift 2 bit:% d \ n",a>>2 );
printf("u nsigned b right_shift 2 bit,% d \ n",b >> 2 );
}
运行结果:
signed a right_shift 2 bit:-2
unsigned b right_shift 2 bit:62
char a= - 8; 负数补码存储
1 1 1 1 1 0 0 0
1 1 1 1 1 1 1 0
舍弃复制
a>> 2
带符号的操作数右移位时,左端出现的空位
按原最左端的符号位复制,无论什么操作数,
移出右端的位被舍弃。
不带符号的操作数右移位时,左端出现的空
位补零。
uns igned char b=248
1 1 1 1 1 0 0 0
0 0 1 1 1 1 1 0
舍弃
补零
b>> 2
uns igned char b=248
1 1 1 1 1 0 0 0
0 0 1 1 1 1 1 0
舍弃
补零
b>> 2
说明:
4) 每右移一位相当于操作数除 2 。
5) a>> 2, b>>2 形式 的 操作并 不 改变操作数 a,b
的值;若 a = a> >2,b = b >> 2 则不同。
三、位操作赋值运算(复合位运算)
运算符 名 称 例 子 等价于
&= 位与赋值 a&=b a=a&b
|= 位或赋值 a|=b a=a|b
^= 位异或赋值 a^=b a=a^b
>>= 右移赋值 a>>=b a=a>>b
<<= 左移赋值 a<<=b a=a<<b
名 称 例 子名 称名 称 例 子例 子
位操作赋值运算的过程是,两个操作数进行位 操作,
然后把结果赋予第一个操作数,为此第一个操作 数必
须是变量,且其值将被改变。
例 [5],编写一个函数 getbits (),从一个 16 位(或 32
位)的单元中取出几位(即该几位保留原值,其 余位
为 0 )函数调用形式为,getbits( v alue,n1,n2)
uns igned getbits( uns igned value,int n1,int n2 ){
uns igned b,c,d;
b = value > > n1; c = ~( ~ 0 << n2 ); d = b&c;
return(d);
}
void main(){
uns igned a; a = ge tbits( 0x ff6f,4,4 );
printf( "a=0x % x \ n",a ); // 运行结果,a=0x 6
}
例 [5],编写一个函数 getbits (),从一个 16 位(或 32
位)的单元中取出几位(即该几位保留原值,其 余位
为 0 )函数调用形式为,getbits( 0 x ff6f,4,4)
value:0xff6f 0 …… 0 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1
b=value >>n1 0 …… 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 0
~0 1 …… 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
~0 <<4 1 …… 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
c=~(~0 <<4 ) 0 …… 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
b 0 …… 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 0
c 0 …… 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
d=b&c 0 …… 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
四、位段
就是以位( bit ) 位单位定义长度的结构体类型成员。
说明:
1) 具体使用中应注意成员的所占位,即长度,及其由
长度限定的存取值域。
2) 一个位段必须分配在同一个存储单元之中,不能跨
两个单元,可以 u n s i g ne d, 0 实现从下以个存储单
元开始存放。
3) 位段可在数值表达式中引用,并由系统自动 转换为
整形数,可用整形噶式输出。
例 [1 - 6],位段运算。
void main(){
struct packed_date{
unsigned a:2; // 结构成员位段 a 所占位 2
unsigned b:6; // 结构成员位段 b 所占位 6
unsigned c:4; // 结构成员位段 c 所占位 4
unsigned d:4; // 结构成员位段 d 所占位 4
unsigned,0; // 单元空余位不用处理
int i; // 结构成员 i
}data; // 接下页
data.a=3;
data.b=4;
data.c=data.a+data.b;
data.d=data.b - data.a;
printf("%d %d \ n",data.c,data.d);
data.i=data.a+data.b+data.c+data.d;
printf("%d \ n",data.i);
}
运行结果:
7 1
15
1 1 0 0 0 1 0 0 0 1 1 1 0 0 0 1 …… 0 …… 0 0 0 0 0 0 1 1 1 1
a:2 b:6 c:4 d:4 16 空 i:32空
注:以机器字长 32 计。
# include <stdio.h>
#include <math.h>
#define EPS 1e - 7
void main(){
double udf_sin(double x); // 用户自定义函数原型说明
double a; scanf("%lf",&a);
printf("%f %f \ n",udf_sin(a),sin(a));
}
double udf_sin( double x ){ // 用户自定义函数
double sum,term,n=1; sum=term=x;
while( fabs(term) > EPS ){
n=n+1;
term=term*( - x*x)/((2*n - 2)*(2*n - 1));Th e end
培 育 英 才 钻 研 科 学
书山有径勤为路
学海无边苦作舟
书山有径勤为路书山有径勤为路
学海无边苦作舟学海无边苦作舟