目录
- 表达式
- 基础
- 算术运算符
- 逻辑和关系运算符
- 赋值运算符
- 递增和递减运算符
- 成员访问运算符
- 条件运算符
- 位运算符
- sizeof运算符
- 逗号运算符
- 类运算符
- 运算符优先级表
表达式
基础
- 当一个对象被用作右值的时候,用的是对象的 值(内容);
- 当对象被用作左值的时候,用的是对象的 身份(在内存中的位置)。
求值顺序
对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为。举个简单的例子,<<运算符没有明确规定何时以及如何对运算对象求值,因此下面的输出表达式是未定义的:
int i = 0 ;
cout << i << " " << ++i << endl; //未定义的,i 和 ++i 不知道谁先求
以下两条经验准则对书写复合表达式有益:
- 1.拿不准的时候最好用括号来强制让表达式的组合关系符合程序逻辑的要求。
- 2.如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象。
算术运算符
一元运算符的优先级最高,接下来是乘法和除法,优先级最低的是加法和减法。下面的所有运算符都满足左结合律,意味着当优先级相同时按照从左向右的顺序进行组合。
在表达式求值之前,小整数类型的运算对象被提升成较大的整数类型,所有运算对象最终会转换成同一类型。
一元负号运算符对运算对象值取负后,返回其(提升后的)副本:
// k是-1024
bool b = true;
bool b2 = -b; // b2是true!
对大多数运算符来说,布尔类型的运算对象将被提升为int 类型。如上所示,布尔变量b的值为真,参与运算时将被提升成整数值1,对它求负后的结果是-1。将-1再转换回布尔值并将其作为b2的初始值,显然这个初始值不等于0,转换成布尔值后应该为1。所以,b2的值是真 !
逻辑和关系运算符
关系运算符作用于算术类型或指针类型,逻辑运算符作用于任意能转换成布尔值的类型。逻辑运算符和关系运算符的返回值都是布尔类型。值为0的运算对象(算术类型或指针类型)表示假,否则表示真。对于这两类运算符来说,运算对象和求值结果都是右值。
短路求值(short-circuit evaluation):
- 对于逻辑与运算符来说,当且仅当左侧运算对象为真时才对右侧运算对象求值。
- 对于逻辑或运算符来说,当且仅当左侧运算对象为假时才对右侧运算对象求值。
关系运算符
- 关系运算符都满足左结合律
因为关系运算符的求值结果是布尔值,所以将几个关系运算符连写在一起会产生意想不到的结果:
//哎哟!这个条件居然拿i<j的布尔值结果和k比较!
if (i < j < k) //若k 大于1则为真!
//正确:当i小于j并且j小于k时条件为真
if (i < j && j < k) {/* ...*/ }
相等性测试与布尔字面值
if (val) {/* ...*/ } //如果val是任意的非0值,条件为真
if (!val) {/* ...*/ } //如果val是0,条件为真
进行比较运算时除非比较的对象是布尔类型,否则不要使用布尔字面值true和false作为运算对象。
if (val == true){/* ...*/ } //只有当val等于1时条件才为真!
但是这种写法存在两个问题:
- 首先,与之前的代码相比,上面这种写法较长而且不太直接
- 更重要的一点是,如果 val 不是布尔值,这样的比较就失去了原来的意义。