B.5 表达式
变量名、函数名、消息表达式、数组名、常量、函数调用、数组引用以及结构和联合引用都可以看作表达式。将一元运算符(在合适的位置)应用到其中一个表达式中的其中,它仍是一个表达式,用二元或三元运算符将两个或多个这样的表达式组合到一起也是这样。最后,括在圆括号内的表达式仍然是表达式。
标识一个数据对象的任何非void类型的表达式名为左值(lvalue)。如果可以为它指派值,它是所谓的可修改左值。
可修改的左值表达式在特定的地方是必需的。位于赋值运算符左侧的表达式必须是一个可修改的左值。一元地址运算符只能应用于可修改的lvalue或函数名。最后,自加自减运算符只能应用于可修改的左值。
B.5.1 Objective-C运算符总结
表B-4总结了Objective-C语言中的各种运算符。这些运算符按其优先级降序列出,组合在一起的运算符具有相同的优先级。
作为演示如何使用表B-4的例子,考虑下面的表达式:
b|c&d*e
与按位OR和按位AND运算符相比,乘法运算符有更高的优先级,因为在表B-4中它出现在这两个位运算符之前。类似地,与按位OR运算符相比,按位AND运算符有更高的优先级,因为在表中前者出现在后者的前面。因此,这个表达式将以
b|(c&(d*e))
来求值。
现在,考虑下面的表达式:
b%c*d
因为在表B-4中取模和乘法运算符出现在同一个组,所以它们具有相同的优先级。这些运算符的结合性是从左到右,表示该表达式以如下方式求值:
(b%c)*d
来求值。
作为另一个例子,表达式
++a->b
将以
++(a->b)
来求值,因为->运算符的优先级比++运算符的优先级高。
最后,因为赋值运算符从右到左结合,所以语句
a=b=0;
将以
a=(b=0);
来求值,这最终导致a和b的值被设为0。对于表达式
x[i]+++i
中,它没有定义编译器将先求加号运算符的左侧的值还是右侧的值。此处,求值的方式会影响结果,因为i的值可能在求x[i]的值之前已经加1。
下面展示另一个在表达式中没有定义求值顺序的例子:
x[i]=++i
在这种情况下,没有定义i的值是在x中的索引使用它的值之前还是之后加1。函数和方法参数的求值顺序也是未定义的。因此,在函数调用
f(i,++i);
或消息表达式
[myFract setTo:i over:++i];
中,可能首先将i加1,因此导致将同一个值作为两个参数发送给函数或方法。
Objective-C语言确保&&和||运算符按照从左到右的顺序求值。此外,在使用&&时,保证如果第一个运算数为0,就不会求第二个运算数的值;在使用||时,保证如果第一个运算数非0,就不会求第二个运算数的值。在生成表达式时应该记住这个事实,例如
if(dataFlag||[myData checkData])
……
因为,在这种情况下,只有在dataFlag的值是0时才调用checkData。作为另一个例子,如果定义数组对象a包含n个元素,则以
if(index>=0&&index<n&&([a objectAtIndex:index]==0))
……
开始的语句只有在index是数组中的有效下标时才引用元素。