每一个表达式都有一个结果,字面值常量也是表达式,其结果就是值本身。除了特殊用法外表达式的结果是右值。是左值的情况也有,比如++i;这个表达式就是一个左值;还有逗号运算符的结果是表达式最右侧操作符德值,如果最右是一个左值的话,那整个逗号表达式就是左值。
表达式涉及到操作符和操作数,操作符有优先级规则,有结合性,还有操作数的求值顺序。就操作数的求值顺序而言,比如f1() * f2();两个函数的返回值进行相乘,但无法确定先调用哪个函数。
操作符%成为“求余”或是“取模”,操作数为整型,其中bool类型也可以。
对于“%”和“/”这两个操作符来说。如果只有一个操作数为负数,那这两种操作的结果(这里仅指绝对值,不考虑符号)都是取决于机器的;取模运算的符号也是取决机器的;但除法操作的结果肯定是负数。举个例子:
21/ -5:依赖机器的,结果是-4或是-5
21% -5:依赖机器的,对应的结果是1或是-4
在逻辑表达式中,逻辑与和逻辑或总是先计算左操作数,再计算右操作数。只有在仅靠左操作数无法判断表达式结果时,才会求解器右操作数。我们称这种运算原则为“短路求值”。
相等测试与bool字面值。由于bool中的true可以转换为1,所以如何判断某值与true相等却成了难题。这里要考虑某值val的类型,如果val是bool类型的,那么正确的判断就是if ( val ) { … };即可。如果val不是bool类型,那判断就和if ( val ==1 ) {…};等价了;假如val是整型,那if ( val )则是当且仅当val为0时为逻辑假,其余的值,无论正负都是逻辑真。
位操作符的操作数是整型,这里的整型不仅可以是正整数,也可以是负整数。但对于负整数的符号位处理方式,不同的机器有着不同的实现,所以尽量使用无符号正整数来作为位运算的操作数。
位运算中的左移和右移操作原则。无符号来说,左移是数值扩大,右侧补0;右移是数值减小,左侧补0。对于有符号来说,其右移过程中,左侧可能是补0将其变成正数,也可能补1不改变其符号,这都依赖于机器。
Cout<<42 + 10;正确,因为+高于<<
Cout<<(10 < 42);也正确,因为有括号
Cout<<10 < 42;错误,因为<<高于关系运算符。Cout<<10之后返回一个ostream的引用,返回引用的目的是可以连续输出,达到流的效果。将一个ostream引用和42对比较是无意义的。
赋值操作的右结合性。
Intival, jval; ival = jval = 0;这是合法的。赋值运算符也有返回值,先执行jval= 0,返回一个整型再赋给ival。赋值运算符具有很低的优先级。
判等和赋值容易出错的地方。If ( i = 42 )这句话实际上是对的,字面解释是把42赋给i,然后判断i的真或假。但这显然是无意义的,这句代码像是被写错的,原意是if ( i== 42 )。为了能避免这样的隐蔽错误,可以写成if ( 42 == i)这样一来,假如少写了个“=”if( 42 = i )就是编译错误,可以及时发现。
关于如何交换两个数的值.
算术方法:a = a + b; b = a – b; a = a – b;
位运算方法: a ^= b; b ^= a; a ^= b;
对于i++和++i的更深层次讨论,在一个长的表达式中有多个关于i的自增和自减操作,这样的表达式的结果是依赖机器的。这里面有一个概念是任何语言的表达式求值都逃不掉的,那就是序点。序点直观来说就是当执行到此序点时必须保证序点前的子表达式已经求出结果。在C++中规定,上一个和下一个序点之间,对象的值至多被修改1次。至于规定表达式中的哪些地方设置序点,这有机器实现决定。值得一说的是在长表达式中不要试图多次对一个对象修改。
I++是右值,++i是左值。
I++的具体实现:
Constint int::operator++(int)
{
IntoldValue = *this;
++(*this);
ReturnoldValue;
}
++i的实现细节:
Int&int::operator++()
{
*this+= 1;
Return*this;
}