购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.2.5 运算符与表达式

C语言对数据有很强的表达能力,具有十分丰富的运算符。运算符就是完成某种特定运算的符号,表达式则是由运算符及运算对象所组成的具有特定含义的一个式子。C语言是一种表达式语言,在任意一个表达式的后面加一个分号“;”就构成了一个表达式语句。由运算符和表达式可以组成C语言程序的各种语句。

运算符按其在表达式中所起的作用,可分为赋值运算符、算术运算符、增量与减量运算符、关系运算符、逻辑运算符、位运算符、复合赋值运算符、逗号运算符、条件运算符、指针和地址运算符、强制类型转换运算符和sizeof运算符等。运算符按其在表达式中与运算对象的关系,又可分为单目运算符、双目运算符和三目运算符等。单目运算符只需要有一个运算对象,双目运算符要求有两个运算对象,三目运算符要求有三个运算对象。掌握各种运算符的意义和使用规则,对于编写正确的C语言程序是十分重要的。

1.赋值运算符

在C语言中,符号“=”是一个特殊的运算符,称之为赋值运算符。赋值运算符的作用是将一个数据的值赋给一个变量,利用赋值运算符将一个变量与一个表达式连接起来的式子称为赋值表达式,在赋值表达式的后面加一个分号“;”便构成了赋值语句。赋值语句的格式如下:

变量=表达式;

该语句的意义是先计算出右边表达式的值,然后将该值赋给左边的变量。上式中的“表达式”还可以是另一个赋值表达式,即C语言允许进行多重赋值。例如:

这些都是合法的赋值语句。在使用赋值运算符“=”时应注意不要与关系运算符“==”相混淆,运算符“==”用来进行相等关系运算。

2.算术运算符

C语言中的算术运算符有:

+加或取正值运算符

-减或取负值运算符

*乘运算符

/除运算符

%取余运算符

上面这些运算符中加、减、乘、除为双目运算符,它们要求有两个运算对象。对于加、减和乘法符合一般的算术运算规则。除法运算有所不同,如果是两个整数相除,其结果为整数,舍去小数部分,例如:5/3的结果为1,5/10的结果为0。如果是两个浮点数相除,其结果为浮点数,例如:5.0/10.0的结果为0.5。取余运算要求两个运算对象均为整型数据,例如:7%4的结果为3。取正值和取负值为单目运算符,它们的运算对象只有一个,分别是取运算对象的正值和负值。

用算术运算符将运算对象连接起来的式子即为算术表达式。算术运算的一般形式为:

表达式1 算术运算符 表达式2

例如:x+y/(a-b),(a+b)*(x-y)都是合法的算术表达式。C语言中规定了运算符的优先级和结合性。在求一个表达式的值时,要按运算符的优先级别进行。算术运算符中取负值(-)的优先级最高,其次是乘法(*)、除法(/)和取余(%)运算符,加法(+)和减法(-)运算符的优先级最低。

需要时可在算术表达式中采用圆括号来改变运算符的优先级,例如在计算表达式x+y/(a-b)的值时,首先计算(a-b),然后再计算 y/(a-b),最后计算 x+y/(a-b)。如果在一个表达式中各个运算符的优先级别相同,则计算时按规定的结合方向进行。例如计算表达式x+y-z的值,由于+和-优先级别相同,计算时按“从左至右”的结合方向,先计算x+y,再计算(x+y)-z。这种“从左至右”的结合方向称为“左结合性”,此外还有“右结合性”。

3.增量和减量运算符

C语言中除了基本的加、减、乘、除运算符之外,还提供一种特殊的运算符:

++增量运算符

--减量运算符

增量和减量是C语言中特有的一种运算符,它们的作用分别是对运算对象做加1和减1运算。例如:++i,i++,--j,j--等。

看起来++i和i++的作用都是使变量i的值加1,但是由于运算符++所处的位置不同,使变量i加1的运算过程也不同。++i(或--i)是先执行i+1(或i-1)操作,再使用i的值,而i++(或i--)则是先使用i的值,再执行i+1(或i-1)操作。

增量运算符++和减量运算符——只能用于变量,不能用于常数或表达式。

例2-1 使用增量“++”和减量“--”运算符的例子。

程序执行结果:

在这个程序例子中使用了Keil C51编译器提供的库函数printf()来完成输出操作,在C语言程序中凡是使用了库函数的,都必须在程序开始处将该库函数的预定义头文件包含进来,才能使程序得到正确的编译和执行,本程序使用了预处理命令#include将库函数printf()的头文件stdio.h包含到程序中。另外,C51中凡是采用scanf()函数和printf()函数进行的输入和输出操作,都是通过单片机串行口实现的,为了使printf()函数能够在μVision4仿真调试状态下正确工作,应在C51源程序中增加如下对8051单片机串行口初始化的语句:

4.关系运算符

C语言中有6种关系运算符:

> 大于

< 小于

>=大于等于

<=小于等于

==等于

!=不等于

前4种关系运算符具有相同的优先级,后两种关系运算符也具有相同的优先级;但前4种的优先级高于后2种。用关系运算符将两个表达式连接起来即成为关系表达式。关系表达式的一般形式为:

表达式1 关系运算符 表达式2

例如:x>y,x+y>z,(x=3)>(y=4)都是合法的关系表达式。

关系运算符通常用来判别某个条件是否满足,关系运算的结果只有0和1两种值。当所指定的条件满足时结果为1,条件不满足时结果为0。

例2-2 使用关系运算符的例子。

程序执行结果(1):

程序执行结果(2):

程序执行结果(3):

在本例中使用了Keil C51编译器提供的输入库函数scanf,与printf函数一样,scanf也是通过8051单片机的串行口实现数据输入的,它的使用方法与printf函数类似。

5.逻辑运算符

C语言中有3种逻辑运算符:

||逻辑或

&&逻辑与

!逻辑非

逻辑运算符用来求某个条件式的逻辑值,用逻辑运算符将关系表达式或逻辑量连接起来就是逻辑表达式。逻辑运算的一般形式为:

例如:x&&y,a||b,!z都是合法的逻辑表达式。

进行逻辑与运算时,首先对条件式1进行判断,如果结果为真(非0值),则继续对条件式2进行判断,当结果也为真时,表示逻辑运算的结果为真(值为1);反之,如果条件式1的结果为假,则不再判断条件式2,而直接给出逻辑运算的结果为假(值为0)。

进行逻辑或运算时,只要两个条件式中有一个为真,逻辑运算的结果便为真(值为1),只有当条件式1和条件式2均不成立时,逻辑运算的结果才为假(值为0)。

进行逻辑非运算时,对条件式的逻辑值直接取反。

逻辑运算符的优先级为(由高至低):!(非)→&&(与)→||(或),即逻辑非的优先级最高。

例2-3 使用逻辑运算符的例子。

程序执行结果(1):

程序执行结果(2):

程序执行结果(3):

程序执行结果(4):

程序执行结果(5):

6.位运算符

能对运算对象进行按位操作是C语言的一大特点,正是由于这一特点使C语言具有了汇编语言的一些功能,从而使之能对计算机的硬件直接进行操作。C语言中共有6种位运算符:

~按位取反

<< 左移

>> 右移

&按位与

^按位异或

|按位或

位运算符的作用是按位对变量进行运算,并不改变参与运算的变量的值。若希望按位改变运算变量的值,则应利用相应的赋值运算。另外位运算符不能用来对浮点型数据进行操作。位运算符的优先级从高到低依次是:按位取反(~)→左移(<<)和右移(>>)→按位与(&)→按位异或(^)→按位或(|)。位运算的一般形式如下:

变量1 位运算符 变量2

表2-6列出了按位取反、按位与、按位或和按位异或的逻辑真值。

表2-6 按位取反、按位与、按位或和按位异或的逻辑真值

例2-4 位逻辑运算。

程序执行结果:

位运算符中的移位操作比较复杂。左移(<<)运算符是用来将变量1的二进制位值向左移动由变量2所指定的位数。例如:a=0x8f(即二进制数10001111),进行左移运算a<<2,就是将a的全部二进制位值一起向左移动2位,其左端移出的位值被丢弃,并在其右端补以相应位数的“0”。因此,移位的结果是a=0x3c(即二进制数(00111100)。

右移(>>)运算符是用来将变量1的二进制位值向右移动由变量2指定的位数。进行右移运算时,如果变量1属于无符号类型数据,则总是在其左端补“0”;如果变量1属于有符号类型数据,则在其左端补入原来数据的符号位(即保持原来的符号不变),其右端的移出位被丢弃。对于a=0x8f,如果a是无符号数,则执行a>>2之后结果为a=0x23(即二进制数00100011);如果a是有符号数,则执行a>>2之后结果为a=0xe3(即二进制数11100011)。

例2-5 移位运算。

程序执行结果:

7.复合赋值运算符

在赋值运算符“=”的前面加上其他运算符,就构成了所谓复合赋值运算符:

+=加法赋值

-=减法赋值

*=乘法赋值

/=除法赋值

%=取模赋值

<<=左移位赋值

>>=右移位赋值

&=逻辑与赋值

|=逻辑或赋值

^=逻辑异或赋值

~=逻辑非赋值

复合赋值运算首先对变量进行某种运算,然后将运算的结果再赋给该变量。复合运算的一般形式为:

变量 复合赋值运算符 表达式

例如:a+=3等价于a=a+3;x*=y+8等价于x=x*(y+8)。凡是二目运算符,都可以和赋值运算符一起组合成复合赋值运算符。采用复合赋值运算符,可以使程序简化,同时还可以提高程序的编译效率。

例2-6 利用复合赋值运算符实现算术运算。

程序执行结果:

例2-7 利用复合赋值运算符实现位逻辑运算。

程序执行结果:

8.逗号运算符

在C语言中逗号“,”是一个特殊的运算符,可以用它将两个(或多个)表达式连接起来,称为逗号表达式。逗号表达式的一般形式为:

表达式1,表达式2,…,表达式n

程序运行时对于逗号表达式的处理,是从左至右依次计算出各个表达式的值,而整个逗号表达式的值是最右边表达式(即表达式n)的值。

例2-8 逗号运算符的使用。

程序执行结果:

在许多情况下,使用逗号表达式的目的只是为了分别得到各个表达式的值,而并不一定要得到和使用整个逗号表达式的值。另外还要注意,并不是在程序的任何地方出现的逗号,都可以认为是逗号运算符。例如函数中的参数也是用逗号来间隔的,上例中库输出函数printf("\n%d%d%d",a,b,c)中的“a,b,c”是函数的三个参数,而不是一个逗号表达式。

9.条件运算符

条件运算符“?:”是C语言中唯一的一个三目运算符,它要求有三个运算对象,用它可以将三个表达式连接构成一个条件表达式。条件表达式的一般形式如下:

逻辑表达式?表达式1:表达式2

其功能是首先计算逻辑表达式,当值为真(非0值)时,将表达式1的值作为整个条件表达式的值;当逻辑表达式的值为假(0值)时,将表达式2的值作为整个条件表达式的值。例如:条件表达式 max=(a>b)?a:b的执行结果是将a和b中较大者赋值给变量max。另外,条件表达式中逻辑表达式的类型可以与表达式1和表达式2的类型不一样。

10.指针和地址运算符

指针是C语言中的一个十分重要的概念,在C语言的数据类型中专门有一种指针类型。变量的指针就是该变量的地址,还可以定义一个指向某个变量的指针变量。为了表示指针变量和它所指向的变量地址之间的关系,C语言提供了两个专门的运算符:

*取内容

&取地址

取内容和取地址运算的一般形式分别为:

取内容运算的含义是将指针变量所指向的目标变量的值赋给左边的变量;取地址运算的含义是将目标变量的地址赋给左边的变量。需要注意的是,指针变量中只能存放地址(即指针型数据),不要将一个非指针类型的数据赋值给一个指针变量。

例2-9 指针及地址运算符的使用。

程序执行结果:

i=5

11.强制类型转换运算符

C语言中的圆括号“()”也可作为一种运算符使用,这就是强制类型转换运算符,它的作用是将表达式或变量的类型强制转换成为所指定的类型。在C语言程序中进行算术运算时,需要注意数据类型的转换。有两种数据类型转换方式,即隐式转换和显式转换。隐式转换是在对程序进行编译时由编译器自动处理的。隐式转换遵循以下规则。

① 所有char型的操作数转换成int型。

② 用运算符连接的两个操作数如果具有不同的数据类型,按以下次序进行转换:如果一个操作数是float类型,则另一个操作数也转换成float类型;如果一个操作数是long类型,则另一个操作数也转换成long类型;如果一个操作数是unsigned类型,则另一个操作数也转换成unsigned类型。

③ 在对变量赋值时发生的隐式转换,将赋值号“=”右边的表达式类型转换成赋值号左边变量的类型。例如,把整型数赋值给字符型变量,则整型数的高8位将丧失;把浮点数赋值给整型变量,则小数部分将丧失。在C语言中只有基本数据类型(即char、int、long和float)可以进行隐式转换。其余的数据类型不能进行隐式转换,例如,我们不能把一个整型数利用隐式转换赋值给一个指针变量,在这种情况下就必须利用强制类型转换运算符来进行显式转换。强制类型转换运算符的一般使用形式为:

(类型)=表达式

显式类型转换在给指针变量赋值时特别有用。例如,预先在 8051 单片机的片外数据存储器(xdata)中定义了一个字符型指针变量px,如果想给这个指针变量赋一初值0xB000,可以写成:px=(char xdata*)0xB000;这种方法特别适合于用标识符来存取绝对地址。

例2-10 强制类型转换运算符的使用。

程序执行结果:

2a f364 3 A

12.sizeof运算符

C语言中提供了一种用于求取数据类型、变量以及表达式的字节数的运算符:sizeof,该运算符的一般使用形式为:

sizeof(表达式)或sizeof(数据类型)

应该注意的是,sizeof是一种特殊的运算符,不要错误地认为它是一个函数。实际上,字节数的计算在程序编译时就完成了,而不是在程序执行的过程中才计算出来的。

例2-11 sizeof运算符的使用。

程序执行结果:

前面对C语言中的各种运算符分别做了介绍,此外还有三个运算符:数组下标运算符“[]”、存取结构或联合中变量的运算符“->”或“.”,它们将在第5章予以介绍。表2-7给出了这些运算符在使用过程中的优先级和结合性。

表2-7 运算符的优先级和结合性

续表 Vt/TmpJIVhDGUj2tmlG0runXiaHW16U1oJtIh69ZwZylqKmiutlpcduD7iMe+5ad

点击中间区域
呼出菜单
上一章
目录
下一章
×