4.7 表达式
表达式其实是一个递归定义的概念:
(1)一个单独的标识符(变量、常量、函数等)是一个表达式。
(2)由表达式和运算符按照语法规则构成的更加复杂的表达式也是表达式。
通俗地讲,表达式就是使用运算符和标识符(操作数)按照语法规则连接起来的算式,因此任何表达式都是有值的。常见的表达式有常量表达式、算术表达式、关系表达式和逻辑表达式及复合表达式。此外还有一些不常用的表达式,例如,逗号表达式、条件运算符(?:)表达式、位运算表达式,等等。
【提示4-13】: 不要把数学中的表达式与计算机语言支持的表达式相混淆。例如:
if(a<b<c) //a<b<c是数学表达式而不是程序表达式
并不表示:
if((a<b)&&(b<c))
而是成了令人费解的if ( (a < b) < c )。
常量表达式就是全部由常量(字面常量、符号常量、枚举常量、布尔常量等)和运算符构成的表达式。由于常量在运行时不能改变值,所以常量表达式没有必要等到运行时才计算,编译器在编译时就可以对它求值。因此,常量表达式也可以定义为:在编译时就可以求值的表达式。
【提示4-14】: 能够在编译时求值的程序元素是否需要分配运行时的存储空间呢?要看它是什么类型的程序元素。例如,基本数据类型的字面常量、枚举常量、sizeof()、常量表达式等就不需要分配存储空间,因此也没有存储类型,但是字符串常量、const常量(尤其是ADT/UDT的const对象)都要分配运行时的存储空间,即有特定的存储类型。
算术表达式就是由算术运算符(+、-、*、/、%、|、&等)和标识符构成的表达式。除了由赋值运算符(=)和算术运算符结合在一起组成的运算符外(如=、+=、-=、*=、/=、%=、|=、&=等),不要使用算术表达式作为单独的语句,因为你并没有保存和使用它的计算结果却要计算机白白地耗费时间去计算它。
关系表达式就是由关系运算符(>、<、>=、<=、==、!=)和标识符构成的表达式,常用来构造条件表达式。所谓条件表达式就是指示计算机执行判断从而有所选择地执行语句序列的表达式。很显然,关系运算符都是二元运算符,两个操作数才能产生关系,单独一个操作数能和谁有关系呢?关系表达式总是返回true(非0值)或false(0)。
逻辑表达式则是由逻辑运算符(&&、||、!)和标识符构成的表达式,其中“!”是一元运算符。逻辑运算符也常用来构造条件表达式。逻辑表达式总是返回true(非0值)或false(0)。
【建议4-1】: 在使用运算符“&&”的表达式中,要尽量把最有可能为false的子表达式放在“&&”的左边;同样在使用运算符“||”的表达式中,要尽量把最有可能为true的子表达式放在“||”的左边。因为C++/C对逻辑表达式的判断采取“突然死亡法”(猝死法):如果“&&”左边的子表达式计算结果为false,则整个表达式就为false,后面的子表达式没有必要再计算;如果“||”左边的子表达式计算结果为true,则整个表达式就为true,因此后面的子表达式没有必要再计算。这种方法可以提高程序的执行效率。
由简单表达式通过算术的、关系的和逻辑的运算组合而成的表达式就是复合表达式(混合表达式),这是我们重点讨论的对象,因为它最有可能存在隐患。
允许复合表达式存在的理由是:
(1)书写简洁,使用简单表达式完成相同功能需要更多周折。
(2)生成的可执行代码更加高效。
但要防止滥用复合表达式。
【提示4-15】: 不要编写太复杂的复合表达式,例如:
i=a>=b&&c<d&&c+f<=g+h; // 复合表达式过于复杂
不要编写多用途的复合表达式,例如:
d = (a = b + c) + r ;
若表达式既求a值又求d值,则应该拆分为两个独立的语句:
a = b + c; d = a + r;
需要注意的是,任何表达式都可以作为单独的语句来用,我们叫做表达式语句。如赋值表达式也叫做赋值语句。