FONT color=#0000ff> 2.6.4 位操作符
2.6.5 ? 操作符
2.6.6 逗号操作符
2.6.7 关于优先级的小结
2.7 表达式
2.7.1 表达式中的类型转换
2.7.2 构成符cast
2.7.3 空格与括号
2.7.4 C语言中的简写形式
| p |
q |
p&&q |
p||q |
!p |
| 0 |
0 |
0 |
0 |
1 |
| 0 |
1 |
0 |
1 |
1 |
| 1 |
0 |
0 |
1 |
0 |
| 1 |
1 |
1 |
1 |
0 |
这一表达式的结果为True。
下表给出了关系和逻辑运算符的相对优先级:
最高 !
>= <=
== !=
&&
最低 ||
同算术表达式一样,在关系或逻辑表达式中也使用括号来修改原计算顺序。
切记,所有关系和逻辑表达式产生的结果不是0就是1,所以下面的程序段不仅正确而且将在屏幕上打印数值1。
int x;
x = 100;
printf("%d",x>10);
2.6.4 位操作符与其它语言不同,C语言支持全部的位操作符( Bitwise Operators)。因为C语言的设计目的是取代汇编语言,所以它必须支持汇编语言所具有的运算能力。位操作是对字节或字中的位(bit)进行测试、置位或移位处理,这里字节或字是针对C标准中的char和int数据类型而言的。位操作不能用于float、double、long double、void或其它复杂类型。表
2 - 7给出了位操作
的操作符。位操作中的AND、OR和NOT(1的补码)的真值表与逻辑运算等价,唯一不同的是位操作是逐位进行运算的。
表2-7 位操作符
| 操作符 |
含义 |
操作符 |
含义 |
| & |
与(AND) |
~ |
1的补(NOT) |
| | |
或(OR) |
>> |
右移 |
| ^ |
异或(XOR) |
<< |
左移 |
下面是异或的真值表。
表2-8 异或的真值表
| p |
q |
p^q |
| 0 |
0 |
0 |
| 1 |
0 |
1 |
| 1 |
1 |
0 |
| 0 |
1 |
1 |
如表2 - 8所示,当且仅当一个操作数为True时,异或的输出为True,否则为Flase。
位操作通常用于设备驱动程序,例如调制解调器程序、磁盘文件管理程序和打印机驱动程序。这是因为位操作可屏蔽掉某些位,如奇偶校验位(奇偶校验位用于确保字节中的其它位不会发生错误通常奇偶校验位是字节的最高位)。
通常我们可把位操作A N D作为关闭位的手段,这就是说两个操作数中任一为0的位,其结果中对应位置为0。例如,下面的函数通过调用函数read_modem( ),从调制解调器端口读入一个字符,并将奇偶校验位置成0。
[例2 - 4 ]
Char get_char_from_modem()
{
char ch;
ch=read_modem(); /*从调制解调器端口中得到一个字符* /
return(ch&127);
}
字节的位8是奇偶位,将该字节与一个位1到位7为1、位8为0的字节进行与操作,可将该字节的奇偶校验位置成0。表达式ch&127正是将ch中每一位同127数字的对应位进行与操作,结果ch的位8被置成了0。在下面的例子中,假定c h接收到字符"A"并且奇偶位已经被置位。
奇偶位
↓
110000001 内容为‘A’的c h,其中奇偶校验位为1
011111111 二进制的127执行与操作
& 与操作
-----------
=010000001 去掉奇偶校验的‘A’
位操作OR与AND操作相反,可用来置位。任一操作数中为1的位将结果的对应位置1。如下所示,128|3的情况是:
1000000 128的二进制
0000011 3的二进制
| 或操作
----------
=1000011 结果
异或操作通常缩写为XOR,当且仅当做比较的两位不同时,才将结果的对应位置位。如下所示,异或操作127 ^ 12 0的情况是:
01111111 127 的二进制
01111000 120 的二进制
^ 异或操作
---------
=00000111 结果
一般来说,位的AND、OR和XOR操作通过对操作数运算,直接对结果变量的每一位分别处理。正是因为这一原因(还有其它一些原因),位操作通常不像关系和逻辑运算符那样用在条件语句中,我们可以用例子说明这一点:假定X = 7,那么x && 8为Ture( 1 ) ,而x & 8却为Flase( 0 )。
记住,关系和逻辑操作符结果不是0就是1。而相似的位操作通过相应处理,结果可为任意值。换言之,位操作可以有0或1以外的其它值,而逻辑运算符的计算结果总是0或1。
移位操作符>>和<<将变量的各位按要求向或向左移动。右移语句通常形式是:
variable >>右移位数
左移语句是:
variable << 左移位数
当某位从一端移出时,另一端移入0(某些计算机是送1,详细内容请查阅相应C编译程序用户手册)。切记:移位不同于循环,从一端移出的位并不送回到另一端去,移去的位永远丢失了,同时在另一端补0。
移位操作可对外部设备(如D/A转换器)的输入和状态信息进行译码,移位操作还可用于整数的快速乘除运算。如表2 - 9所示(假定移位时补0),左移一位等效于乘2,而右移一位等效于除以2。
表2-9 用移位操作进行乘和除
| 字符x |
每个语句执行后的x |
x的值 |
| x=7 |
00000111 |
7 |
| x<<1 |
00001110 |
14 |
| x<<3 |
01110000 |
112 |
| x<<2 |
11000000 |
192 |
| x>>1 |
01100000 |
96 |
| x>>2 |
00011000 |
24 |
每左移一位乘2,注意x < < 2后,原x的信息已经丢失了,因为一位已经从一端出,每右移一位相当于被2除,注意,乘后再除时,除操作并不带回乘法时已经丢掉的高位。
反码操作符为~。~的作用是将特定变量的各位状态取反,即将所有的1位置成0,所有的0位置成1。
位操作符经常用在加密程序中,例如,若想生成一个不可读磁盘文件时,可以在文件上做一些位操作。最简单的方法是用下述方法,通过1的反码运算,将每个字节的每一位取反。
原字节 00101100
第一次取反码 11010011
第二次取反码 00101100
注意,对同一行进行连续的两次求反,总是得到原来的数字,所以第一次求反表示了字节的编码,第二次求反进行译码又得到了原来的值。
可以用下面的函数encode( )对字符进行编码。
[例2 - 5 ]
char encode(ch)
char ch;
{
return (~ch);
}
2.6.5 ?操作符
C语言提供了一个可以代替某些if - then - else语句的简便易用的操作符?。该操作符是三元的,其一般形式为:
EXP1? EXE2: EXP3
EXP1,EXP2和EXP3是表达式,注意冒号的用法和位置。
操作符“?”作用是这样的,在计算EXP1之后,如果数值为True,则计算EXP2,并将结果作为整个表达式的数值;如果E XP1的值为Flase,则计算EXP3,并以它的结果作为整个表达式的值,请看下例:
x = 10;
y = x> 9? 100: 200;
例中,赋给y的数值是100,如果x被赋给比9小的值,y的值将为200,若用if - else语句改写,有下面的等价程序:
x = 10;
if(x>9) y=100;
else y=200;
有关C语言中的其它条件语句将在第3章进行讨论。
2.6.6 逗号操作符
作为一个操作符,逗号把几个表达式串在一起。逗号操作符的左侧总是作为void(无值),这意味着其右边表达式的值变为以逗号分开的整个表达式的值。例如:
x = ( y = 3 , y + 1 ) ;
这行将3赋给y,然后将4赋给x,因为逗号操作符的优先级比赋值操作符优先级低,所以必须使用括号。
实际上,逗号表示操作顺序。当它在赋值语句右边使用时,所赋的值是逗号分隔开的表中最后那个表达式的值。例如,
y = 10;
x = (y = y - 5 , 2 5 / y ) ;
执行后,x的值是5,因为y的起始值是1 0,减去5之后结果再除以2 5,得到最终结果。
在某种意义上可以认为,逗号操作符和标准英语的and是同义词。
2.6.7 关于优先级的小结
表2 - 1 0列出了C语言所有操作符的优先级,其中包括将在本书后面讨论的某些操作符。注意,所有操作符(除一元操作符和?之外)都是左结合的。一元操作符( *,&和-)及操作符“?”则为右结合。
表2-10 C语言操作符的优先级
最高级 ()[] →
!~ ++ -- -(type) * & sizeof
* / %
+ -
<< >>
<= >=
== !=
& ^ |
&&
||
?
= += -= *= /=
最低级,
2.7 表达式
表达式由运算符、常量及变量构成。C语言的表达式基本遵循一般代数规则,有几点却是与C语言紧密相关的,以下将分别加以讨论。
2.7.1 表达式中的类型转换
混合于同一表达式中的不同类型常量及变量,应均变换为同一类型的量。C语言的编译程序将所有操作数变换为与最大类型操作数同类型。变换以一次一操作的方式进行。具体规则如下:
1 ) 所有char及short int 型量转为int型,所有float转换为double。
2) 如操作数对中一个为long double ,另一个转换为long double。① 要不然,一个为double,另一个转为doub le。② 要不然,一个为long,另一个转为long。③ 要不然,一个为unsigned,另一个转为unsigned。
一旦运用以上规则。每一对操作数均变为同类型。注意,规则2 )有几种必须依次应用的条件。
图2 - 1示出了类型转换。首先, char ch转换成int,且floatf 转换成double;然后ch /i的结果转换成doubl e,因为f * d是double;最后由于这次两个操作数都是double,所以结果也是double。.
2.7.2 构成符cast
可以通过称为cast的构成符强迫一表达式变为特定类型。其一般形式为:
(type)expression
( type)是标准C语言中的一个数据类型。例如,为确保表达式x / 2的结果具有类型float,可写为:
(float)x / 2
通常认为cast是操作符。作为操作符, cast是一元的,并且同其它一元操作符优先级相同。
虽然cast在程序中用得不多,但有时它的使用的确很有价值。例如,假设希望用一整数控制循环,但在执行计算时又要有小数部分。
[例2 - 6 ]
main()
{
int i;
for(i+1;i<=100;++i)
printf("%d/2 is :%f",i,(float)i/2);
}
若没有cast( float),就仅执行一次整数除;有了cast就可保证在屏幕上显示答案的小数部分。
2.7.3 空格与括号
为了增加可读性,可以随意在表达式中插入tab和空格符。例如,下面两个表达式是相同的。
x = 10 / y *( 127 / x );
x = 10 / y *( 127 / x );
冗余的括号并不导致错误或减慢表达式的执行速度。我们鼓励使用括号,它可使执行顺序更清楚一些。例如,下面两个表达式中哪个更易读一些呢?
x = y / 2 - 34 * temp & 127;
x = ( y / 2 ) - ( ( 34 * temp) & 127);
2.7.4 C语言中的简写形式
C语言提供了某些赋值语句的简写形式。例如语句:
x = x + 10;
在C语言中简写形式是:
x + = 10;
这组操作符对+ =通知编译程序将X + 1 0的值赋予X。这一简写形式适于C语言的所有二元操作符(需两个操作数的操作符)。在C语言中,variable=variable1 operator expression;与variable1 operator=expression相同。
请看另一个例子:
x = x - 1 0 0 ;
其等价语句是
x - = 100;
简写形式广泛应用于专业C语言程序中,希望读者能熟悉它。