Antigloss 最后修改于 2006-12-28
1. 自增运算符(Increment Operator)
自增运算符 ++ 使操作数的值增 1,其操作数必须为可变左值(您可以简单地把可变左值理解为变量)。++ 可以置于操作数前面,也可以放在后面。例如:
++n ;
n++ ;
这两个语句产生的结果都是使 n 增 1,可以说没什么区别。使用以下语句得到的效果也是一样的:
n = n + 1 ;
尽管上面两个语句中,++ 前置和后置没有区别。但是,++ 前置和后置其实是有区别的。例如:
int n = 1, post, pre;
post = n++;
pre = ++n;
对于 post = n++; 这个语句,post 得到 n 自增前的值,因为 n++ 的值为 1。也就是说,这个语句执行完后,post 的值是 1,而 n 的值变成 2。而 pre = ++n; 这个语句,pre 得到 n 自增后的值,因为 ++n 的值为 3。也就是说,这个语句执行完后,pre 的值是 3,n 的值也是 3。
总之,无论前置还是后值,++ 都会使其操作数的值增 1。不同的是,++ 前置时,自增表达式(如 ++n)的值等于其操作数自增后的值;++ 后置时,自增表达式(如 n++)的值等于其操作数自增前的值。例如:
int n = 5, post = 1, pre = 1;
pre = ++n + pre; // 运算结束后 pre 为 7,n 为 6
n = 5;
post = n++ + post; // 运算结束后 post 为 6,n 为 6
上例中,++n 的值等于 n 自增后的值,即 6,所以 pre 最后得到的值为 7。n++ 的值等于 n 自增前的值,即 5,所以 post 最后得到的值为 6。
2. 自减运算符(Decrement Operator)
自减运算符 -- 使操作数的值减 1。同样,-- 的操作数也必须为可变左值。-- 可以置于操作数前面,也可以放在后面。例如:
--n ;
n-- ;
自减运算符和自增运算符非常相似,区别只在于自减运算符使操作数减 1,而自增运算符使操作数增 1。例如:
int n = 5, post = 1, pre = 1;
pre = --n + pre; // 运算结束后 pre 为 5
n = 5;
post = n-- + post; // 运算结束后 post 为 6
3. 优先级
自增运算符和自减运算符的优先级比 + - * / 的优先级要高。因此,n*m++; 表示 n*(m++); 而不是 (n * m)++; 。而且 (n * m)++; 是错误的。因为 ++ 和 -- 的操作数只能是可变左值(modifiable lvalue),而 n * m 不是。
注意,不要把优先级和运算顺序混淆了。例如:
int x = 1, y = 2, z;
z = (x + y++) * 3; // 运算结束后 z 为 9,y 为 3
用数字代替上面的语句得:
z = (1 + 2) * 3;
优先级表明的是 ++ 作用于 y,而不是 (x + y),但它决定不了 y 的值何时增 1。我们可以肯定的是,在整个语句执行完毕后,y 的值肯定增加了。但是,我们不知道该语句执行中的什么时候,y 的值会增 1,这是由编译器决定的。
==========================================================================
以下内容引自《C 语言常见问题集》 原著:Steve Summit 翻译:朱群英, 孙 云
http://c-faq-chn.sourceforge.net/ccfaq/index.html
http://www.eskimo.com/~scs/C-faq/top.html
==========================================================================
4.3 对于代码 int i = 3; i = i++; 不同编译器给出不同的结果, 有的为 3, 有的为 4, 哪个是正确的?
没有正确答案;这个表达式无定义。参见问题 3.1, 3.7 和 11.32。 同时注意, i++ 和 ++i 都不同于 i+1。如果你要使 i 自增 1, 使用 i=i+1, i+=1, i++ 或 ++i, 而不是任何组合, 参见问题 3.10。
12.35 有人说 i = i++ 的行为是未定义的, 但是我刚在一个兼容 ANSI 的编译器上测试, 得到了我希望的结果。
面对未定义行为的时候, 包括范围内的实现定义行为和未确定行为, 编译器可以做任何实现, 其中也包括你所有期望的结果。但是依靠这个实现却不明智。参加问题 7.4, 11.31, 11.32 和 11.34。
4.2 使用我的编译器,下面的代码 int i=7; printf("%d\n", i++ * i++); 返回 49?不管按什么顺序计算, 难道不该打印出56吗?
尽管后缀自加和后缀自减操作符 ++ 和 -- 在输出其旧值之后才会执行运算, 但这里的``之后"常常被误解。没有任何保证确保自增或自减会在输出变量原值之后和对表达式的其它部分进行计算之前立即进行。也不能保证变量的更新会在表达式 ``完成" (按照 ANSI C 的术语, 在下一个 ``序列点" 之前, 参见问题 3.7) 之前的某个时刻进行。本例中, 编译器选择使用变量的旧值相乘以后再对二者进行自增运算。
包含多个不确定的副作用的代码的行为总是被认为未定义。(简单而言, ``多个不确定副作用" 是指在同一个表达式中使用导致同一对象修改两次或修改以后又被引用的自增, 自减和赋值操作符的任何组合。这是一个粗略的定义; 严格的定义参见问题 3.7, ``未定义" 的含义参见问题 11.32。) 甚至都不要试图探究这些东西在你的编译器中是如何实现的 (这与许多 C 教科书上的弱智练习正好相反); 正如 K&R 明智地指出, ``如果你不知道它们在不同的机器上如何实现, 这样的无知可能恰恰会有助于保护你。
4.7 我怎样才能理解复杂表达式?``序列点" 是什么?
序列点是一个时间点(在整个表达式全部计算完毕之后或在 ||、 &&、 ? : 或逗号 运算符处, 或在函数调用之前), 此刻尘埃落定, 所有的副作用都已确保结束。 ANSI/ISO C 标准这样描述:
在上一个和下一个序列点之间, 一个对象所保存的值至多只能被表达式的计算修改一次。而且前一个值只能用于决定将要保存的值。
第二句话比较费解。它说在一个表达式中如果某个对象需要写入, 则在同一表达式中对该对象的访问应该只局限于直接用于计算将要写入的值。这条规则有效地限制了只有能确保在修改之前才访问变量的表达式为合法。例如 i = i+1 合法, 而 a[i] = i++ 则非法 (参见问题 3.1)。
参见下边的问题 3.8。
==========================================================================
参考资料:C Primer 5th Edition
The C Programming Language 2nd Edition
C99 标准
C 语言常见问题集
本文版权归 蚂蚁的 C/C++ 标准编程 以及 作者 antigloss 共同所有,转载请注明原作者和出处。谢谢。