表达式
-
左值和右值
当一个对象被用作右值时,用的是对象的值(内容);被用作左值时,用的是对象的身份(在内存中的位置)在需要右值的地方可以用左值替代,使用左值的内容;但是不能把右值当作左值使用
-
优先级
规定运算对象的组合方式,括号无视优先级 -
求值顺序
与优先级和结合律无关
在一条复合语句中,如果出现多个求值表达式,同时它们会改变同一对象的状态,则它会产生未定义的行为
f()+g()*h()+j();
,没有严格的调用顺序,因此会存在类似数据冒险的情况
如果改变了某个运算对象的值,在表达式的其他地方就不要再使用这个运算对象 -
取余运算
取余运算的运算对象必须是整数类型
运算结果的符号匹配第一个数字的符号,即m%n
的结果符号与 m 的符号相同 -
逻辑运算符
短路求值&&和||
先求左侧运算对象的结果再求右侧运算对象的结果,当左侧结果无法确定表达式的结果时才求右侧结果
左侧运算对象可以保证右侧运算对象求值过程的正确性和安全性,例如 先判断下标是否有效,再依下标访问对象(使用&&) -
关系运算符
if(i < j < k);
错误
if(i < j && j < k);
正确
避免使用布尔字面值作为运算对象,例如if(val == true)
,true 会转换为 1 -
赋值运算符
赋值结果返回的是左侧运算对象,且是一个左值
如果左右侧运算对象类型不同,则 右侧运算对象将转为左侧运算对象类型
如果在一个赋值表达式的左右两边使用同一运算对象,避免出现改变该对象的做法,例如*p = toupper(*p++);
-
递增和递减运算符
建议使用前置版本
如果需要用到改变前的值,则使用后置版本 -
sizeof
sizeof(type)
,返回指定类型的大小sizeof expr
,返回表达式结果类型的大小
-
逗号运算符
常用于普通 for 循环,需要额外变量控制循环条件的时候 -
类型转换
-
隐式转换
- 算术转换,为了保证精度
- 初始化时,初始值转换为变量的类型;赋值时,右侧运算对象转换为左侧运算对象的类型
- 整型提升
- 一般情况下,有符号类型转换为无符号类型(具有不定性,不建议)
- 数组转换为指针
- 指针转换
常量 0 和字面量nullptr
可以转换成任意指针类型
指向任意非常量的指针能转换成void*
指向任意对象的指针能转换成const void*
- 转换成常量(
const
)
非常量转化为常量引用或者顶层const
指针(通过临时量实现) - 类类型定义转换
string 对象与字符串字面量
-
显式转换
cast-name<type>(expr)
static_cast
不包含底层const
,例如 int 到 double 等const_cast
去掉const
性质(常量对象转换为非常量对象,只改变常量属性)
例如,const char *p;
char *p1 = const_cast<char *>(p)
- reinterpret_cast
不建议使用,例如int *
到char *
-