半开玩笑半严肃:为什么我不能++i++
用类 C 语言,特别是 C#?
我希望它增加值,在我的表达式中使用它,然后再次增加。
Though the short answer "it's not an lvalue" is correct, that's perhaps just begging the question. Why isn't it an lvalue? Or, as we say in C#, a variable.
The reason is because you cannot have your cake and eat it too. Work it out logically:
First off, the meaning of a ++ operator in C#, whether postfix or prefix, is "take the value of this variable, increment the value, assign the new value to the variable, and produce a value as a result". The value produced as the result is either the original value or the incremented value, depending on whether it was a postfix or a prefix. But either way, you produce a value.
Second, the value of a variable is always the current contents of that variable. (Modulo certain bizarre threading scenarios that would take us far afield.)
I hope you agree that these are perfectly sensible rules.
Now it should be clear why the result of i++ cannot be a variable, but in case it isn't, let me make it clear:
Suppose i is 10. The meaning of i++ should be "get the value of i — 10 — increment it — 11 — store it — i is now 11 — and give the original value as the result — 10". So when you say print(i++) it should print 10, and 11 should be stored in i.
Now suppose the meaning of i++ is to return the variable, not the value. You say print(i++) and what happens? You get the value of i — 10 — increment it — 11 — store it — i is now 11 — and give the variable back as a result. What's the current value of the variable? 11! Which is exactly what you DON'T want to print.
In short, if i++ returned a variable then it would be doing exactly the opposite of the intended meaning of the operator! Your proposal is logically inconsistent, which is why no language does it that way.
简短回答:i++
不是“左值”,因此不能成为分配的主题。
因为您关心下一个程序员维护(或尝试重写)您的代码,在您因违反流行惯例而被解雇很久之后。
I tested (++i,i++) as a workaround:
#include <stdio.h>
int main(){
int i=0;
printf(" i: %i\n", i );
printf(" (++i,i++): %i\n", (++i,i++) );
printf(" i: %i\n", i );
}
Result:
i: 0
(++i,i++): 1
i: 2
因为结果i++
不是左值。
我相信增量(或减量)运算符需要一个左值来分配。但是 ++i 不是左值,它是一个表达式。精通编译器的人可能能够澄清这种约束是否有任何技术原因。
从C# 3.0 规范的第 7.5.9 节:
后缀递增或递减操作的操作数必须是分类为变量、属性访问或索引器访问的表达式。运算的结果是与操作数相同类型的值。如果后缀递增或递减操作的操作数是属性或索引器访问,则属性或索引器必须同时具有 get 和 set 访问器。如果不是这种情况,则会发生编译时错误。
此外,将首先评估后增量表达式 ( ),因为它比前增量 ( ) 运算符i++
具有更高的优先级。++i
From C# specification:
The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. The result of the operation is a value of the same type as the operand.
An increment operator can only be applied to a variable (and ㏇) and it returns a value (not a variable). You cannot apply increment to a value (simply because there is no variable to assign the result to) so in C# you can increment a variable only once.
The situation is actually different for C++. According to C++ specification:
prefix increment or decrement is an lvalue expression
which means that in C++ you can call increment on the result of prefix increment or decrement. I.g. the following C++ code is actually valid:
#include <iostream>
using namespace std;
int main()
{
int i = 13;
(--i)++;
cout<<i<<endl;
(++i)--;
cout<<i<<endl;
return 0;
}
NB: The term lvalue is used in C and C++ only. And for the sake of diversity in C the result of prefix increment is actually rvalue so you can't increment increment in C.
C# language uses term variable_reference for a similar concept:
A variable_reference is an expression that is classified as a variable. A variable_reference denotes a storage location that can be accessed both to fetch the current value and to store a new value.