基本的运算符,包括=、+、-、*和/(赋值运算符和加减乘除)。
一. 首先讨论赋值运算符
在C语言中‘=’不是传统意义上的‘等于’,而是‘赋值’,C语言中的‘等于’为‘==’。对于一个基本的语句:
a=2;
在这个语句中,赋值运算符左边的字母是一个变量,右边是赋给该变量的值。赋值运算符的动作是从右到左,因此该语句读为‘把2的值赋给a'.
这个语句牵涉到几个术语:左值、右值和操作数。
左值(lvalue):用于标识一个特定的数据对象的名字或者表达式(例子中的变量a)。
右值(rvalue):指的是能赋给可修改的左值的量(例子中的a)。
操作数(operand):运算符操作的对象。
运算符中,加减乘除被称为二元运算符,因为需要两个操作数。还有表示正(+)负(-)的运算符,称为一元运算符(只需要一个操作数)。
在运算符中,需要注意的问题有:
1.优先级问题:决定了式子中的运算顺序。实际编程时,对于优先级很明确的运算符可以不用理会,但对于 记不清或者容易出错的运算符,可以加括号控制一下,即直观简便又不容易出错。
2.求值的顺序问题:对于一元运算符(+、-)和赋值运算符(=),求值顺序为从右到左,其余(加减乘除) 顺序为从左到右。
二. 其它的一些运算符
sizeof运算符:以字节(1个字节被定义为char类型所占用的空间的大小,一般为8位,但在一些情况下很有可 能不同)为单位,返回操作数的大小。操作数可以是一个具体的对象(比如变量a),也可以 是一个数据类型(例如int)。为了保持一致性,最好写成,sizeof(**)的形式(带括号)。
取模运算符(%):求余数的运算符(例如14%5=4),需要注意的是,该运算符两边必须为整数。
(++,--):该运算符的优先级除了括号外,最高。++a,在代入变量a之前,加1.a++代入变量a,结束该该 次运算后,加1(注意两者加1的不同时机).
三. 表达式
表达式是由运算符和操作数组合而形成的。注意:每个表达式都有一个值。例如q>3,如果该表达式为真,则该表达式的值为1,若为假,则返回值为0.
四. 语句
在C中,语句在结束处用一个分号(;)标示。例如q>3只是一个表达式,而q>3;则是一个语句。程序是一系列带有某种必须的标点的语句的集合。复合语句或代码块,是由花括号里面的一个或多个语句组成的。
五. 副作用和顺序点
从C语言的角度讲,C的目的是为了对表达式求值。所谓副作用就是对数据对象或者文件的修改。例如:a=2的副作用就是将变量a的值置为2,例如自加运算符和自减运算符(对变量的计算而不是对表达式的计算)主要被当做副作用来使用。
顺序点:程序中执行的一点。在该点处,所有的副作用在进入下一步之前被计算。在C中,语句中的‘;’标志了一个顺序点,任何一个完整的表达式(不从属于另外一个表达式之中,独立的一个表达式)的结束也是一个顺序点。对于下面这个代码:
对于a++<10,由于是一个完整的表达式,所以当a与10比较完后(这里是一个顺序点),进入printf函数之前,数值加1.所以这个程序的输出为:
再考虑下一个例子:
在b的赋值语句中,(4+a++)显然是属于一个大的表达式之中,因此不是一个顺序点,所以只有到语句结束后(;处),a才开始计算,并且自加两次,因此该程序的输出为:
本节需要注意的问题:类型转换。
语句和表达式中通常只使用一种类型的变量和常量。如果混合使用,C会使用规则自动完成类型转换。基本规则如下:
1. 有符号和无符号的char和short类型将自动转换为int(在一些机器中,short和int有相同的大小,此时unsigned short 比int大,所以被转换为unsigned int)。
2. 类型级别从高到底依次为:long double、double、float、unsigned long long、long long、unsigned long、long、unsigned int、int(short和char被转换为 int 或者特殊情况下的unsigned int)。
3. 在包含两种类型的多种计算中,两者都被转换为类型里较高的级别,而到最后赋值时,则被强制转换为被赋值变量的类型。在被转换的过程中,如果转变成了大的类型,叫做提升(promotion),这个无损害,但是如果大的类型被降级(demotion),则会因为低级的类型不够大,而不能存储完整的数,而出现错误。
4. 作为函数的参数被传递时,char和short被转换为int,float被转换为double。
为了避免自动类型数据转换,尤其是降级的发生,可以用指派(cast)的方法,来表明你知道自己在做数据转换。如:
c=a+b中,是自动完成数据类型的,从float类型的5.2被转换为int型的5,d中是先被转换为a=3,b=1后,再计算。因此两者的结果为: