C语言程序设计
2002 年第二章 基本数据类型和运算
2.3.5 位运算
(1) 整数在机内的表示:
A,任何整数在计算机内以二进制码形式存放。
无符号整数,所有位都用来表示数据的值:
例,unsigned char ch; 中,
ch分配一个字节能表示的数值范围,0 ~ 255
有符号整数,存储长度的最高位用来表示符号,
0表示正数,1表示负数,
例,int i; 中,
16位机中,i分配两个字节能表示的数值范围,-32768 ~
32767
正数用原码表示 ; 负数用补码表示,
例,int i=12; i的存储形式,
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
例,int j=- 1; j的存储形式为 1的反码加 1:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
符号位
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
例,int j=- 13; j的存储形式为,
首先,13的存储形式为,
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1
求反反码加 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
例,int j=- 32768; j的存储形式为 32768的反码加 1:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
求反加 1
注意,当超出范围时引起错误结果,
例,int j=32768; j的存储形式为 32768的原码,与- 32768
的存储完全相同,:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
例,int j=- 32769; j的存储形式为 1的反码加 1:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
(2) 运算符:
~(求反 ) &(按位与 ) | (按位或 ) ^ (按位加,异或 )
<<(左移 ) >> (右移 )
(3) 操作数类型:必须为整型,
(4) 运算符功能,
( 一 ) 求反运算符 ( ~ ):
单目,将操作数的每一位取反 (1变 0,0变 1)
例,int a=15;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
表达式 ~a (或 ~15)的存储形式为,( -16)
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
(二 ) 按位与、或、加( &,|,^),双目
int i=0127,j=0137531;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1
26=64 24=16 20=1
i & j?81
(二 ) 按位或 ( | )
int i=0127,j=0137531;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 1 1 1
i | j? -16545
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1
i | j的绝对值为,214+27+25+20=16384+128+32+1=16545
(二 ) 按位加( ^),
int i=0127,j=0137531;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 0 0 0 1 1 1 0
表达式,i ^ j?- 16626
(三 ) 左移运算符( <<)、右移运算符( >>),
优先级,见表,高于关系运算符,低于算术运算符。
表达式形式,e<<n e>>n
e为整数,n为正整数功能,e<<n 将 e的数向左移 n位(即乘 2的 n次方),高端 n位被移出丢掉,空出的低 n位填 0。 e和 n自身的值未变。
例,0X3a4f << 3
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 1 1 1 0 1 0 0 1 0 0 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 0 1 0 0 1 0 0 1 1 1 1 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 1 1 1 0 1 0 0 1 0 0 1 1 1 1
e>>n 将 e的数向右移 n位(即除 2的 n次方),低端 n位被移出丢掉。
如果 e为无符号整数,空出的 n位填 0。
如果 e为有符号整数,空出的 n位填符号位的值。
例,unsigned int i= 0X3a4f 表达式 i>>3
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 1 1 1 0 1 0 0 1 0 0 1
类型转换,e和 n的类型不同时不需要转换,但 e中有 char、
short时要实行整数提升。
运算结果,为整型、与 e的类型相同。
例,short a=32767;
表达式,a>>4 的结果为 2047,类型为 int。
例,int i= 0Xfa4f 表达式 i>>3 或 0Xfa4f >>3
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 0 1 0 0 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 0 1 0 0 1 0 0 1 1 1 1
例:写一表达式,用整数 p的低字节作为结果的低字节,k的低字节作为结果的高字节。
(1) 取 p的低字节,屏蔽高字节,p&0xFF 或 p&0377
(2) 取 k的低字节,屏蔽高字节,k&0xFF 或 p&0377
(3) 将 k的低字节移到高字节,(k&0xFF) << 8
(4) 将( 1)和( 3)的结果按为或,得最后结果:
( p&0xFF) | (k&0xFF) << 8
注意,( 2)和( 3)可简化为,k << 8
则最后结果:
( p&0xFF) | k << 8
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1
两数按位与例:写一表达式,用整数 p的高字节作为结果的低字节,k的高字节作为结果的高字节。
(1) 将 p的高字节移到低字节,并且屏蔽可能符号位在高字节部分设置的 1:
(p>>8) & 0x ff 或 (p>>8) & 0x 377
(2) 取 k的高字节,屏蔽低字节:
k&0xFF00
(3) 将( 1)和( 2)的结果按为或,得最后结果:
(p>>8) & 0x ff | k&0xFF00
例:设 x,m,n为无符号整数( 16位),0≤m ≤ 15,
1 ≤ n ≤16-m,求由整数 x的第 m位开始向右的 n位组成数。
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 0 0 0 1 0 1 1 0 1 0 1 1 1
m=9,n=6
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1
结果
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 0 0 0 1 0 1 1 0 1 0 1 1 1
--------15 - m 位 --------------------n 位 -----------? <--- m-n+1 位 --?
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 0 1 0 1 1 1 0 0 0 0 0 0
-------- n 位 ----------------------------- 16-n 位 -----------------?
x<<15-m
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
(x<<15-m)>>16-n
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 1 0 1 0 1 1 0 1 0 1 1 1
--------15 - m 位 --------------------n 位 -----------? <--- m-n+1 位 --?
x>>(m-n+1)
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
解法 2:若 x 为有符号整数,可能为负数,如,
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
需要求出下面的数和上面的数按位与
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
-------------------- 16-n 位 ------------------------- n 位 ---------?
0Xffff
0Xffff<<n
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
~(0Xffff<<n)
x>>(m-n+1) & ~(0Xffff<<n)
2002 年第二章 基本数据类型和运算
2.3.5 位运算
(1) 整数在机内的表示:
A,任何整数在计算机内以二进制码形式存放。
无符号整数,所有位都用来表示数据的值:
例,unsigned char ch; 中,
ch分配一个字节能表示的数值范围,0 ~ 255
有符号整数,存储长度的最高位用来表示符号,
0表示正数,1表示负数,
例,int i; 中,
16位机中,i分配两个字节能表示的数值范围,-32768 ~
32767
正数用原码表示 ; 负数用补码表示,
例,int i=12; i的存储形式,
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
例,int j=- 1; j的存储形式为 1的反码加 1:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
符号位
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
例,int j=- 13; j的存储形式为,
首先,13的存储形式为,
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1
求反反码加 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
例,int j=- 32768; j的存储形式为 32768的反码加 1:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
求反加 1
注意,当超出范围时引起错误结果,
例,int j=32768; j的存储形式为 32768的原码,与- 32768
的存储完全相同,:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
例,int j=- 32769; j的存储形式为 1的反码加 1:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
(2) 运算符:
~(求反 ) &(按位与 ) | (按位或 ) ^ (按位加,异或 )
<<(左移 ) >> (右移 )
(3) 操作数类型:必须为整型,
(4) 运算符功能,
( 一 ) 求反运算符 ( ~ ):
单目,将操作数的每一位取反 (1变 0,0变 1)
例,int a=15;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
表达式 ~a (或 ~15)的存储形式为,( -16)
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
(二 ) 按位与、或、加( &,|,^),双目
int i=0127,j=0137531;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1
26=64 24=16 20=1
i & j?81
(二 ) 按位或 ( | )
int i=0127,j=0137531;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 1 1 1
i | j? -16545
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1
i | j的绝对值为,214+27+25+20=16384+128+32+1=16545
(二 ) 按位加( ^),
int i=0127,j=0137531;
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 1 0 1 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 1 1 1 0 0 0 0 1 1 1 0
表达式,i ^ j?- 16626
(三 ) 左移运算符( <<)、右移运算符( >>),
优先级,见表,高于关系运算符,低于算术运算符。
表达式形式,e<<n e>>n
e为整数,n为正整数功能,e<<n 将 e的数向左移 n位(即乘 2的 n次方),高端 n位被移出丢掉,空出的低 n位填 0。 e和 n自身的值未变。
例,0X3a4f << 3
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 1 1 1 0 1 0 0 1 0 0 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 0 1 0 0 1 0 0 1 1 1 1 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 1 1 1 0 1 0 0 1 0 0 1 1 1 1
e>>n 将 e的数向右移 n位(即除 2的 n次方),低端 n位被移出丢掉。
如果 e为无符号整数,空出的 n位填 0。
如果 e为有符号整数,空出的 n位填符号位的值。
例,unsigned int i= 0X3a4f 表达式 i>>3
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 1 1 1 0 1 0 0 1 0 0 1
类型转换,e和 n的类型不同时不需要转换,但 e中有 char、
short时要实行整数提升。
运算结果,为整型、与 e的类型相同。
例,short a=32767;
表达式,a>>4 的结果为 2047,类型为 int。
例,int i= 0Xfa4f 表达式 i>>3 或 0Xfa4f >>3
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 0 1 0 0 1 0 0 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 0 1 0 0 1 0 0 1 1 1 1
例:写一表达式,用整数 p的低字节作为结果的低字节,k的低字节作为结果的高字节。
(1) 取 p的低字节,屏蔽高字节,p&0xFF 或 p&0377
(2) 取 k的低字节,屏蔽高字节,k&0xFF 或 p&0377
(3) 将 k的低字节移到高字节,(k&0xFF) << 8
(4) 将( 1)和( 3)的结果按为或,得最后结果:
( p&0xFF) | (k&0xFF) << 8
注意,( 2)和( 3)可简化为,k << 8
则最后结果:
( p&0xFF) | k << 8
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1
两数按位与例:写一表达式,用整数 p的高字节作为结果的低字节,k的高字节作为结果的高字节。
(1) 将 p的高字节移到低字节,并且屏蔽可能符号位在高字节部分设置的 1:
(p>>8) & 0x ff 或 (p>>8) & 0x 377
(2) 取 k的高字节,屏蔽低字节:
k&0xFF00
(3) 将( 1)和( 2)的结果按为或,得最后结果:
(p>>8) & 0x ff | k&0xFF00
例:设 x,m,n为无符号整数( 16位),0≤m ≤ 15,
1 ≤ n ≤16-m,求由整数 x的第 m位开始向右的 n位组成数。
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 0 0 0 1 0 1 1 0 1 0 1 1 1
m=9,n=6
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1
结果
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 0 0 0 1 0 1 1 0 1 0 1 1 1
--------15 - m 位 --------------------n 位 -----------? <--- m-n+1 位 --?
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 0 1 0 1 1 1 0 0 0 0 0 0
-------- n 位 ----------------------------- 16-n 位 -----------------?
x<<15-m
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
(x<<15-m)>>16-n
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 1 0 1 0 1 1 0 1 0 1 1 1
--------15 - m 位 --------------------n 位 -----------? <--- m-n+1 位 --?
x>>(m-n+1)
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
解法 2:若 x 为有符号整数,可能为负数,如,
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
需要求出下面的数和上面的数按位与
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
-------------------- 16-n 位 ------------------------- n 位 ---------?
0Xffff
0Xffff<<n
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
-------------------- 16-n 位 ------------------------- n 位 ---------?
~(0Xffff<<n)
x>>(m-n+1) & ~(0Xffff<<n)